{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "“cifar-classifier-tpu.ipynb”的副本",
      "version": "0.3.2",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "TPU"
  },
  "cells": [
    {
      "cell_type": "code",
      "metadata": {
        "id": "z0DRPKl39290",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import numpy as np\n",
        "import pickle\n",
        "import os\n",
        "import urllib\n",
        "import zipfile \n",
        "import tarfile\n",
        "from six.moves import urllib\n",
        "\n",
        "from __future__ import absolute_import\n",
        "from __future__ import division\n",
        "from __future__ import print_function\n",
        "\n",
        "# tensorflow imports\n",
        "import tensorflow as tf\n",
        "from tensorflow.contrib.training import HParams\n",
        "\n",
        "# tf.keras imports\n",
        "from tensorflow.keras import Model\n",
        "from tensorflow.keras.layers import Dense, Conv2D, Activation, Flatten\n",
        "from tensorflow.keras.layers import BatchNormalization, AveragePooling2D, Input\n",
        "from tensorflow.keras.preprocessing.image import ImageDataGenerator\n",
        "\n",
        "# import for showing the confusion matrix\n",
        "import itertools\n",
        "from sklearn.metrics import confusion_matrix\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EJJ9RthRS9Fv",
        "colab_type": "text"
      },
      "source": [
        "Define hyperparameters for training"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "KZtezQ4qD-lU",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "hparams = HParams(\n",
        "    n_classes=10,  # number of different classes in dataset\n",
        "    learning_rate=1e-3,  # fixed learning rate\n",
        "    train_batch_size=200,  # training batch size\n",
        "    val_batch_size=200,  # validation batch size\n",
        "    test_batch_size=32,  # testing batch size\n",
        "    n_epochs=10,  # number of epochs to train\n",
        "    input_name='input_1',  # name of the input tensor for first layer of Keras model\n",
        "    data_dir='/tmp/cifar-data/',  # path to data directory\n",
        "    checkpoint_dir='/tmp/checkpoints/'  # path to model checkpoint directory\n",
        ")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BsL72f44TA3I",
        "colab_type": "text"
      },
      "source": [
        "## Monitor training using TensorBoard"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BXSBbyK1FyBh",
        "colab_type": "text"
      },
      "source": [
        "First, let's download and install the awesome tool [ngrok](https://ngrok.com/). Ngrok allows us to create a public URL to access the localhost of the ipython environment within Google Colab. This allows us to access the TensorBoard within the browser of your local machine."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "L35DdtT_FOXP",
        "colab_type": "code",
        "outputId": "99554389-54a7-4955-ed9e-6d58171793c6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 251
        }
      },
      "source": [
        "! wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip\n",
        "! unzip -o ngrok-stable-linux-amd64.zip"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "--2019-05-14 08:47:21--  https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip\n",
            "Resolving bin.equinox.io (bin.equinox.io)... 54.174.228.92, 52.4.95.48, 52.73.94.166, ...\n",
            "Connecting to bin.equinox.io (bin.equinox.io)|54.174.228.92|:443... connected.\n",
            "HTTP request sent, awaiting response... 200 OK\n",
            "Length: 16529980 (16M) [application/octet-stream]\n",
            "Saving to: ‘ngrok-stable-linux-amd64.zip.2’\n",
            "\n",
            "\r          ngrok-sta   0%[                    ]       0  --.-KB/s               \r         ngrok-stab  11%[=>                  ]   1.74M  8.38MB/s               \rngrok-stable-linux- 100%[===================>]  15.76M  40.6MB/s    in 0.4s    \n",
            "\n",
            "2019-05-14 08:47:21 (40.6 MB/s) - ‘ngrok-stable-linux-amd64.zip.2’ saved [16529980/16529980]\n",
            "\n",
            "Archive:  ngrok-stable-linux-amd64.zip\n",
            "  inflating: ngrok                   \n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EB5P9HvKEblD",
        "colab_type": "text"
      },
      "source": [
        "Now, we run `ngrok` in the `ipython` environment and tunnel the data to a public random URL using ngrok."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YwZrIjZkEEYu",
        "colab_type": "code",
        "outputId": "896bd439-a1a0-4781-c21b-d685aded35d4",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 71
        }
      },
      "source": [
        "# kill all running ngrok instances\n",
        "!pkill -f ngrok\n",
        "\n",
        "# Execute tensorboard\n",
        "!rm rf /tmp/checkpoints\n",
        "!mkdir /tmp/checkpoints\n",
        "LOG_DIR = '/tmp/checkpoints/'\n",
        "get_ipython().system_raw(\n",
        "    'tensorboard --logdir {} --host 0.0.0.0 --port 6006 &'\n",
        "    .format(LOG_DIR)\n",
        ")\n",
        "\n",
        "# execute ngrok\n",
        "get_ipython().system_raw('./ngrok http 6006 &')"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "rm: cannot remove 'rf': No such file or directory\n",
            "rm: cannot remove '/tmp/checkpoints': Is a directory\n",
            "mkdir: cannot create directory ‘/tmp/checkpoints’: File exists\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gkCnSnAREdny",
        "colab_type": "text"
      },
      "source": [
        "The below code should output a URL containg the TensorBoard visualizations for the classifier we are about to train and evaluate."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "3Imio4YREFzg",
        "colab_type": "code",
        "outputId": "6512ef08-7977-4788-ab75-f2f176204991",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "# Do the tunneling\n",
        "! curl -s http://localhost:4040/api/tunnels | python3 -c \\\n",
        "    \"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])\""
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "https://da286a9d.ngrok.io\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0KqmhIDXTKK7",
        "colab_type": "text"
      },
      "source": [
        "## Data download and preprocessing"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VuC2mMKOIIRJ",
        "colab_type": "text"
      },
      "source": [
        "This code is boilerplate code for downloading and preprocessing of the CIFAR-10 dataset. Credits to [Hvass-Labs](https://github.com/Hvass-Labs/TensorFlow-Tutorials/blob/master/cifar10.py)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "2EpQ-iJN94G1",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# URL for the data-set on the internet.\n",
        "data_url = \"https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz\"\n",
        "\n",
        "# Width and height of each image.\n",
        "img_size = 32\n",
        "\n",
        "# Number of channels in each image, 3 channels: Red, Green, Blue.\n",
        "num_channels = 3\n",
        "\n",
        "# Length of an image when flattened to a 1-dim array.\n",
        "img_size_flat = img_size * img_size * num_channels\n",
        "\n",
        "# Number of classes.\n",
        "num_classes = hparams.n_classes\n",
        "\n",
        "########################################################################\n",
        "# Various constants used to allocate arrays of the correct size.\n",
        "\n",
        "# Number of files for the training-set.\n",
        "_num_files_train = 5\n",
        "\n",
        "# Number of images for each batch-file in the training-set.\n",
        "_images_per_file = 10000\n",
        "\n",
        "# Total number of images in the training-set.\n",
        "# This is used to pre-allocate arrays for efficiency.\n",
        "_num_images_train = _num_files_train * _images_per_file\n",
        "\n",
        "########################################################################\n",
        "# Private functions for downloading, unpacking and loading data-files.\n",
        "\n",
        "\n",
        "def download(base_url, filename, download_dir):\n",
        "    \"\"\"\n",
        "    Download the given file if it does not already exist in the download_dir.\n",
        "    :param base_url: The internet URL without the filename.\n",
        "    :param filename: The filename that will be added to the base_url.\n",
        "    :param download_dir: Local directory for storing the file.\n",
        "    :return: Nothing.\n",
        "    \"\"\"\n",
        "\n",
        "    # Path for local file.\n",
        "    save_path = os.path.join(download_dir, filename)\n",
        "\n",
        "    # Check if the file already exists, otherwise we need to download it now.\n",
        "    if not os.path.exists(save_path):\n",
        "        # Check if the download directory exists, otherwise create it.\n",
        "        if not os.path.exists(download_dir):\n",
        "            os.makedirs(download_dir)\n",
        "\n",
        "        print(\"Downloading\", filename, \"...\")\n",
        "\n",
        "        # Download the file from the internet.\n",
        "        url = base_url + filename\n",
        "        file_path, _ = urllib.request.urlretrieve(url=url,\n",
        "                                                  filename=save_path)\n",
        "\n",
        "        print(\" Done!\")\n",
        "\n",
        "\n",
        "def maybe_download_and_extract(url=data_url, download_dir=hparams.data_dir):\n",
        "    \"\"\"\n",
        "    Download and extract the data if it doesn't already exist.\n",
        "    Assumes the url is a tar-ball file.\n",
        "    :param url:\n",
        "        Internet URL for the tar-file to download.\n",
        "        Example: \"https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz\"\n",
        "    :param download_dir:\n",
        "        Directory where the downloaded file is saved.\n",
        "        Example: \"data/CIFAR-10/\"\n",
        "    :return:\n",
        "        Nothing.\n",
        "    \"\"\"\n",
        "\n",
        "    # Filename for saving the file downloaded from the internet.\n",
        "    # Use the filename from the URL and add it to the download_dir.\n",
        "    filename = url.split('/')[-1]\n",
        "    file_path = os.path.join(download_dir, filename)\n",
        "\n",
        "    # Check if the file already exists.\n",
        "    # If it exists then we assume it has also been extracted,\n",
        "    # otherwise we need to download and extract it now.\n",
        "    if not os.path.exists(file_path):\n",
        "        # Check if the download directory exists, otherwise create it.\n",
        "        if not os.path.exists(download_dir):\n",
        "            os.makedirs(download_dir)\n",
        "\n",
        "        # Download the file from the internet.\n",
        "        file_path, _ = urllib.request.urlretrieve(url=url,\n",
        "                                                  filename=file_path)\n",
        "\n",
        "        print()\n",
        "        print(\"Download finished. Extracting files.\")\n",
        "\n",
        "        if file_path.endswith(\".zip\"):\n",
        "            # Unpack the zip-file.\n",
        "            zipfile.ZipFile(file=file_path, mode=\"r\").extractall(download_dir)\n",
        "        elif file_path.endswith((\".tar.gz\", \".tgz\")):\n",
        "            # Unpack the tar-ball.\n",
        "            tarfile.open(name=file_path, mode=\"r:gz\").extractall(download_dir)\n",
        "\n",
        "        print(\"Done.\")\n",
        "    else:\n",
        "        print(\"Data has apparently already been downloaded and unpacked.\")\n",
        "\n",
        "\n",
        "def _get_file_path(filename=\"\"):\n",
        "    \"\"\"\n",
        "    Return the full path of a data-file for the data-set.\n",
        "\n",
        "    If filename==\"\" then return the directory of the files.\n",
        "    \"\"\"\n",
        "\n",
        "    return os.path.join(hparams.data_dir, \"cifar-10-batches-py/\", filename)\n",
        "\n",
        "\n",
        "def _unpickle(filename):\n",
        "    \"\"\"\n",
        "    Unpickle the given file and return the data.\n",
        "\n",
        "    Note that the appropriate dir-name is prepended the filename.\n",
        "    \"\"\"\n",
        "\n",
        "    # Create full path for the file.\n",
        "    file_path = _get_file_path(filename)\n",
        "\n",
        "    print(\"Loading data: \" + file_path)\n",
        "\n",
        "    with open(file_path, mode='rb') as file:\n",
        "        # In Python 3.X it is important to set the encoding,\n",
        "        # otherwise an exception is raised here.\n",
        "        data = pickle.load(file,encoding='bytes')\n",
        "\n",
        "    return data\n",
        "\n",
        "\n",
        "def _convert_images(raw):\n",
        "    \"\"\"\n",
        "    Convert images from the CIFAR-10 format and\n",
        "    return a 4-dim array with shape: [image_number, height, width, channel]\n",
        "    where the pixels are floats between 0.0 and 1.0.\n",
        "    \"\"\"\n",
        "\n",
        "    # Convert the raw images from the data-files to floating-points.\n",
        "    raw_float = np.array(raw, dtype=float) / 255.0\n",
        "\n",
        "    # Reshape the array to 4-dimensions.\n",
        "    images = raw_float.reshape([-1, num_channels, img_size, img_size])\n",
        "\n",
        "    # Reorder the indices of the array.\n",
        "    images = images.transpose([0, 2, 3, 1])\n",
        "\n",
        "    return images\n",
        "\n",
        "\n",
        "def _load_data(filename):\n",
        "    \"\"\"\n",
        "    Load a pickled data-file from the CIFAR-10 data-set\n",
        "    and return the converted images (see above) and the class-number\n",
        "    for each image.\n",
        "    \"\"\"\n",
        "\n",
        "    # Load the pickled data-file.\n",
        "    data = _unpickle(filename)\n",
        "\n",
        "    # Get the raw images.\n",
        "    raw_images = data[b'data']\n",
        "\n",
        "    # Get the class-numbers for each image. Convert to numpy-array.\n",
        "    cls = np.array(data[b'labels'])\n",
        "\n",
        "    # Convert the images.\n",
        "    images = _convert_images(raw_images)\n",
        "\n",
        "    return images, cls\n",
        "\n",
        "\n",
        "def load_class_names():\n",
        "    # Load the class-names from the pickled file.\n",
        "    raw = _unpickle(filename=\"batches.meta\")[b'label_names']\n",
        "\n",
        "    # Convert from binary strings.\n",
        "    names = [x.decode('utf-8') for x in raw]\n",
        "\n",
        "    return names\n",
        "\n",
        "\n",
        "def load_training_data():\n",
        "    \"\"\"\n",
        "    Load all the training-data for the CIFAR-10 data-set.\n",
        "\n",
        "    The data-set is split into 5 data-files which are merged here.\n",
        "\n",
        "    Returns the images, class-numbers and one-hot encoded class-labels.\n",
        "    \"\"\"\n",
        "\n",
        "    # Pre-allocate the arrays for the images and class-numbers for efficiency.\n",
        "    images = np.zeros(shape=[_num_images_train, img_size, img_size, num_channels], dtype=float)\n",
        "    cls = np.zeros(shape=[_num_images_train], dtype=int)\n",
        "\n",
        "    # Begin-index for the current batch.\n",
        "    begin = 0\n",
        "\n",
        "    # For each data-file.\n",
        "    for i in range(_num_files_train):\n",
        "        # Load the images and class-numbers from the data-file.\n",
        "        images_batch, cls_batch = _load_data(filename=\"data_batch_\" + str(i + 1))\n",
        "\n",
        "        # Number of images in this batch.\n",
        "        num_images = len(images_batch)\n",
        "\n",
        "        # End-index for the current batch.\n",
        "        end = begin + num_images\n",
        "\n",
        "        # Store the images into the array.\n",
        "        images[begin:end, :] = images_batch\n",
        "\n",
        "        # Store the class-numbers into the array.\n",
        "        cls[begin:end] = cls_batch\n",
        "\n",
        "        # The begin-index for the next batch is the current end-index.\n",
        "        begin = end\n",
        "\n",
        "    return images, cls\n",
        "\n",
        "\n",
        "def load_validation_data():\n",
        "\n",
        "    images, cls = _load_data(filename=\"test_batch\")\n",
        "\n",
        "    images = images[5000:, :, :, :]\n",
        "    cls = cls[5000:]\n",
        "\n",
        "    return images, cls\n",
        "\n",
        "def load_testing_data():\n",
        "\n",
        "\n",
        "    images, cls = _load_data(filename=\"test_batch\")\n",
        "\n",
        "    images = images[:5000, :, :, :]\n",
        "    cls = cls[:5000]\n",
        "\n",
        "    return images, cls"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eiCehG29Urjk",
        "colab_type": "text"
      },
      "source": [
        "# Network architecture\n",
        "\n",
        "The below code defines the architecture of the neural network we are going to train. We will be using the infamous Resnet architecture with Shortcut connections and bottlenecs. The paper may be found [here](https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/He_Deep_Residual_Learning_CVPR_2016_paper.pdf).\n",
        "\n",
        "We will be using the `tensorflow.keras` API - TensorFlow's implementation of the Keras API specification. This is a high-level API to build and train models that includes first-class support for TensorFlow-specific functionality. Keras is able to use TensorFlow as its backend for tensor processing during training and inference, making Keras easy-to-use but also just as fast as pure TensorFlow models.\n",
        "\n",
        "The model code is part of the Keras examples and may be found [here](https://github.com/keras-team/keras/blob/master/examples/cifar10_resnet.py)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "9mj6sUIhU009",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def resnet_layer(inputs,\n",
        "                 num_filters=16,\n",
        "                 kernel_size=3,\n",
        "                 strides=1,\n",
        "                 activation='relu',\n",
        "                 batch_normalization=True,\n",
        "                 conv_first=True):\n",
        "    \"\"\"2D Convolution-Batch Normalization-Activation stack builder\n",
        "    # Arguments\n",
        "        inputs (tensor): input tensor from input image or previous layer\n",
        "        num_filters (int): Conv2D number of filters\n",
        "        kernel_size (int): Conv2D square kernel dimensions\n",
        "        strides (int): Conv2D square stride dimensions\n",
        "        activation (string): activation name\n",
        "        batch_normalization (bool): whether to include batch normalization\n",
        "        conv_first (bool): conv-bn-activation (True) or\n",
        "            bn-activation-conv (False)\n",
        "    # Returns\n",
        "        x (tensor): tensor as input to the next layer\n",
        "    \"\"\"\n",
        "    conv = Conv2D(num_filters,\n",
        "                  kernel_size=kernel_size,\n",
        "                  strides=strides,\n",
        "                  padding='same',\n",
        "                  kernel_initializer='he_normal',\n",
        "                  kernel_regularizer=tf.keras.regularizers.l2(1e-4))\n",
        "\n",
        "    x = inputs\n",
        "    if conv_first:\n",
        "        x = conv(x)\n",
        "        if batch_normalization:\n",
        "            x = BatchNormalization()(x)\n",
        "        if activation is not None:\n",
        "            x = Activation(activation)(x)\n",
        "    else:\n",
        "        if batch_normalization:\n",
        "            x = BatchNormalization()(x)\n",
        "        if activation is not None:\n",
        "            x = Activation(activation)(x)\n",
        "        x = conv(x)\n",
        "    return x\n",
        "\n",
        "\n",
        "def resnet_v2(input_shape, batch_size=1024,depth=20, num_classes=10):\n",
        "    \"\"\"ResNet Version 2 Model builder [b]\n",
        "    Stacks of (1 x 1)-(3 x 3)-(1 x 1) BN-ReLU-Conv2D or also known as\n",
        "    bottleneck layer\n",
        "    First shortcut connection per layer is 1 x 1 Conv2D.\n",
        "    Second and onwards shortcut connection is identity.\n",
        "    At the beginning of each stage, the feature map size is halved (downsampled)\n",
        "    by a convolutional layer with strides=2, while the number of filter maps is\n",
        "    doubled. Within each stage, the layers have the same number filters and the\n",
        "    same filter map sizes.\n",
        "    Features maps sizes:\n",
        "    conv1  : 32x32,  16\n",
        "    stage 0: 32x32,  64\n",
        "    stage 1: 16x16, 128\n",
        "    stage 2:  8x8,  256\n",
        "    # Arguments\n",
        "        input_shape (tensor): shape of input image tensor\n",
        "        depth (int): number of core convolutional layers\n",
        "        num_classes (int): number of classes (CIFAR10 has 10)\n",
        "    # Returns\n",
        "        model (Model): Keras model instance\n",
        "    \"\"\"\n",
        "    if (depth - 2) % 9 != 0:\n",
        "        raise ValueError('depth should be 9n+2 (eg 56 or 110 in [b])')\n",
        "    # Start model definition.\n",
        "    num_filters_in = 16\n",
        "    num_res_blocks = int((depth - 2) / 9)\n",
        "\n",
        "    inputs = Input(shape=input_shape,\n",
        "                   batch_size=batch_size)\n",
        "    # v2 performs Conv2D with BN-ReLU on input before splitting into 2 paths\n",
        "    x = resnet_layer(inputs=inputs,\n",
        "                     num_filters=num_filters_in,\n",
        "                     conv_first=True)\n",
        "\n",
        "    # Instantiate the stack of residual units\n",
        "    for stage in range(3):\n",
        "        for res_block in range(num_res_blocks):\n",
        "            activation = 'relu'\n",
        "            batch_normalization = True\n",
        "            strides = 1\n",
        "            if stage == 0:\n",
        "                num_filters_out = num_filters_in * 4\n",
        "                if res_block == 0:  # first layer and first stage\n",
        "                    activation = None\n",
        "                    batch_normalization = False\n",
        "            else:\n",
        "                num_filters_out = num_filters_in * 2\n",
        "                if res_block == 0:  # first layer but not first stage\n",
        "                    strides = 2    # downsample\n",
        "\n",
        "            # bottleneck residual unit\n",
        "            y = resnet_layer(inputs=x,\n",
        "                             num_filters=num_filters_in,\n",
        "                             kernel_size=1,\n",
        "                             strides=strides,\n",
        "                             activation=activation,\n",
        "                             batch_normalization=batch_normalization,\n",
        "                             conv_first=False)\n",
        "            y = resnet_layer(inputs=y,\n",
        "                             num_filters=num_filters_in,\n",
        "                             conv_first=False)\n",
        "            y = resnet_layer(inputs=y,\n",
        "                             num_filters=num_filters_out,\n",
        "                             kernel_size=1,\n",
        "                             conv_first=False)\n",
        "            if res_block == 0:\n",
        "                # linear projection residual shortcut connection to match\n",
        "                # changed dims\n",
        "                x = resnet_layer(inputs=x,\n",
        "                                 num_filters=num_filters_out,\n",
        "                                 kernel_size=1,\n",
        "                                 strides=strides,\n",
        "                                 activation=None,\n",
        "                                 batch_normalization=False)\n",
        "            x = tf.keras.layers.add([x, y])\n",
        "\n",
        "        num_filters_in = num_filters_out\n",
        "\n",
        "    # Add classifier on top.\n",
        "    # v2 has BN-ReLU before Pooling\n",
        "    x = BatchNormalization()(x)\n",
        "    x = Activation('relu')(x)\n",
        "    x = AveragePooling2D(pool_size=8)(x)\n",
        "    y = Flatten()(x)\n",
        "    outputs = Dense(num_classes,\n",
        "                    activation='softmax',\n",
        "                    kernel_initializer='he_normal')(y)\n",
        "\n",
        "    # Instantiate model.\n",
        "    model = Model(inputs=inputs, outputs=outputs)\n",
        "\n",
        "    model.compile(loss='sparse_categorical_crossentropy',\n",
        "                  optimizer=tf.keras.optimizers.Adam(lr=hparams.learning_rate),\n",
        "                  metrics=['accuracy'])\n",
        "\n",
        "    return model"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BfGrJgWdVVg3",
        "colab_type": "text"
      },
      "source": [
        "# Fit the classifier\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3GYTmAo5n40B",
        "colab_type": "text"
      },
      "source": [
        "First, let's make sure we are connected to a TPU runtime. The below lines should output a list of 8 TPU devices connected to our session. If not, we receive an error."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "LQTlFmtYbfM1",
        "colab_type": "code",
        "outputId": "3d203d84-da8d-41e6-e0a8-a32eb448e9a5",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 251
        }
      },
      "source": [
        "import os\n",
        "import pprint\n",
        "import tensorflow as tf\n",
        "\n",
        "if 'COLAB_TPU_ADDR' not in os.environ:\n",
        "  print('ERROR: Not connected to a TPU runtime; please see the first cell in this notebook for instructions!')\n",
        "else:\n",
        "  tpu_address = 'grpc://' + os.environ['COLAB_TPU_ADDR']\n",
        "  print ('TPU address is', tpu_address)\n",
        "\n",
        "  with tf.Session(tpu_address) as session:\n",
        "    devices = session.list_devices()\n",
        "    \n",
        "  print('TPU devices:')\n",
        "  pprint.pprint(devices)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "TPU address is grpc://10.33.189.106:8470\n",
            "TPU devices:\n",
            "[_DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:CPU:0, CPU, -1, 403388712430402658),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:XLA_CPU:0, XLA_CPU, 17179869184, 6311906932210768775),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:0, TPU, 17179869184, 14994271124770219574),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:1, TPU, 17179869184, 10848082943016525842),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:2, TPU, 17179869184, 6646040197563992967),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:3, TPU, 17179869184, 8166324418970126545),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:4, TPU, 17179869184, 11249807291052467621),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:5, TPU, 17179869184, 5676563344467051414),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:6, TPU, 17179869184, 3129620792747927706),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU:7, TPU, 17179869184, 12907245032044196888),\n",
            " _DeviceAttributes(/job:tpu_worker/replica:0/task:0/device:TPU_SYSTEM:0, TPU_SYSTEM, 17179869184, 9999872032194223686)]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zxfLg369ZTKo",
        "colab_type": "text"
      },
      "source": [
        "\n",
        "In the below code, we first load the training, validation, and testing data. Then we define a Keras ImageDataGenerator which performs on-the-fly augmentation of the training images in order to increase the number of training samples and thus reduces the risk of overfitting the training data set.\n",
        "\n",
        "The actual classifier training happens in line 46 with the command `resnet_model.fit_generator(...)`."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "dweQdKK2a9qj",
        "colab_type": "code",
        "outputId": "9cbeb453-3063-4eae-f36a-6a7e6c289f6f",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 359
        }
      },
      "source": [
        "tf.logging.set_verbosity(tf.logging.DEBUG)\n",
        "\n",
        "resnet_model = resnet_v2((32, 32, 3), depth=110, num_classes=hparams.n_classes)\n",
        "\n",
        "# This address identifies the TPU we'll use when configuring TensorFlow.\n",
        "TPU_WORKER = 'grpc://' + os.environ['COLAB_TPU_ADDR']\n",
        "tf.logging.set_verbosity(tf.logging.INFO)\n",
        "\n",
        "resnet_model = tf.contrib.tpu.keras_to_tpu_model(\n",
        "    resnet_model,\n",
        "    strategy=tf.contrib.tpu.TPUDistributionStrategy(\n",
        "        tf.contrib.cluster_resolver.TPUClusterResolver(TPU_WORKER)))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "INFO:tensorflow:Querying Tensorflow master (grpc://10.33.189.106:8470) for TPU system metadata.\n",
            "INFO:tensorflow:Found TPU system:\n",
            "INFO:tensorflow:*** Num TPU Cores: 8\n",
            "INFO:tensorflow:*** Num TPU Workers: 1\n",
            "INFO:tensorflow:*** Num TPU Cores Per Worker: 8\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:CPU:0, CPU, -1, 403388712430402658)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:XLA_CPU:0, XLA_CPU, 17179869184, 6311906932210768775)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:0, TPU, 17179869184, 14994271124770219574)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:1, TPU, 17179869184, 10848082943016525842)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:2, TPU, 17179869184, 6646040197563992967)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:3, TPU, 17179869184, 8166324418970126545)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:4, TPU, 17179869184, 11249807291052467621)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:5, TPU, 17179869184, 5676563344467051414)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:6, TPU, 17179869184, 3129620792747927706)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:7, TPU, 17179869184, 12907245032044196888)\n",
            "INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU_SYSTEM:0, TPU_SYSTEM, 17179869184, 9999872032194223686)\n",
            "WARNING:tensorflow:tpu_model (from tensorflow.contrib.tpu.python.tpu.keras_support) is experimental and may change or be removed at any time, and without warning.\n",
            "INFO:tensorflow:Cloning Adam {'lr': 0.0010000000474974513, 'beta_1': 0.8999999761581421, 'beta_2': 0.9990000128746033, 'decay': 0.0, 'epsilon': 1e-07, 'amsgrad': False}\n",
            "INFO:tensorflow:Cloning Adam {'lr': 0.0010000000474974513, 'beta_1': 0.8999999761581421, 'beta_2': 0.9990000128746033, 'decay': 0.0, 'epsilon': 1e-07, 'amsgrad': False}\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "VQWJ-urr99OC",
        "colab_type": "code",
        "outputId": "c2f297e1-2418-4bcb-bf24-9533df7864a6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 3889
        }
      },
      "source": [
        "# Download and extract CIFAR-10 data\n",
        "maybe_download_and_extract()\n",
        "\n",
        "# training data\n",
        "x_train, y_train = load_training_data()\n",
        "\n",
        "# Validation data\n",
        "x_val, y_val = load_validation_data()\n",
        "\n",
        "# Testing data\n",
        "x_test, y_test = load_testing_data()\n",
        "\n",
        "# Define callbacks\n",
        "callbacks = [\n",
        "  tf.keras.callbacks.TensorBoard(log_dir=hparams.checkpoint_dir)\n",
        "]\n",
        "\n",
        "# This will do preprocessing and realtime data augmentation:\n",
        "datagen = ImageDataGenerator(\n",
        "    featurewise_center=False,  # set input mean to 0 over the dataset\n",
        "    samplewise_center=False,  # set each sample mean to 0\n",
        "    featurewise_std_normalization=False,  # divide inputs by std of the dataset\n",
        "    samplewise_std_normalization=False,  # divide each input by its std\n",
        "    zca_whitening=False,  # apply ZCA whitening\n",
        "    zca_epsilon=1e-06,  # epsilon for ZCA whitening\n",
        "    rotation_range=0,  # randomly rotate images in the range (degrees, 0 to 180)\n",
        "    # randomly shift images horizontally (fraction of total width)\n",
        "    width_shift_range=0.1,\n",
        "    # randomly shift images vertically (fraction of total height)\n",
        "    height_shift_range=0.1,\n",
        "    # set mode for filling points outside the input boundaries\n",
        "    fill_mode='nearest',\n",
        "    cval=0.,  # value used for fill_mode = \"constant\"\n",
        "    horizontal_flip=True,  # randomly flip images\n",
        "    vertical_flip=False)\n",
        "\n",
        "# Compute quantities required for feature-wise normalization\n",
        "# (std, mean, and principal components if ZCA whitening is applied).\n",
        "datagen.fit(x_train)\n",
        "\n",
        "# Fit the model on the batches generated by datagen.flow().\n",
        "resnet_model.fit_generator(\n",
        "    datagen.flow(x_train, y_train, batch_size=200),\n",
        "    validation_data=(x_val, y_val),\n",
        "    epochs=100,\n",
        "    steps_per_epoch = 250,\n",
        "    callbacks=callbacks)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Data has apparently already been downloaded and unpacked.\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/data_batch_1\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/data_batch_2\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/data_batch_3\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/data_batch_4\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/data_batch_5\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/test_batch\n",
            "Loading data: /tmp/cifar-data/cifar-10-batches-py/test_batch\n",
            "Epoch 1/100\n",
            "INFO:tensorflow:New input shapes; (re-)compiling: mode=train (# of cores 8), [TensorSpec(shape=(25,), dtype=tf.int32, name='core_id_40'), TensorSpec(shape=(25, 32, 32, 3), dtype=tf.float32, name='input_3_10'), TensorSpec(shape=(25, 1), dtype=tf.int32, name='dense_2_target_30')]\n",
            "INFO:tensorflow:Overriding default placeholder.\n",
            "INFO:tensorflow:Cloning Adam {'lr': 0.0010000000474974513, 'beta_1': 0.8999999761581421, 'beta_2': 0.9990000128746033, 'decay': 0.0, 'epsilon': 1e-07, 'amsgrad': False}\n",
            "INFO:tensorflow:Remapping placeholder for input_3\n",
            "INFO:tensorflow:KerasCrossShard: <tensorflow.python.keras.optimizers.Adam object at 0x7fb55ad4e198> []\n",
            "INFO:tensorflow:Started compiling\n",
            "INFO:tensorflow:Finished compiling. Time elapsed: 542.9245471954346 secs\n",
            "INFO:tensorflow:Setting weights on TPU model.\n",
            "INFO:tensorflow:CPU -> TPU lr: 0.0010000000474974513 {0.001}\n",
            "INFO:tensorflow:CPU -> TPU beta_1: 0.8999999761581421 {0.9}\n",
            "INFO:tensorflow:CPU -> TPU beta_2: 0.9990000128746033 {0.999}\n",
            "INFO:tensorflow:CPU -> TPU decay: 0.0 {0.0}\n",
            "WARNING:tensorflow:Cannot update non-variable config: epsilon\n",
            "WARNING:tensorflow:Cannot update non-variable config: amsgrad\n",
            "249/250 [============================>.] - ETA: 7s - loss: 3.0780 - acc: 0.4613 INFO:tensorflow:New input shapes; (re-)compiling: mode=eval (# of cores 8), [TensorSpec(shape=(25,), dtype=tf.int32, name='core_id_50'), TensorSpec(shape=(25, 32, 32, 3), dtype=tf.float32, name='input_3_10'), TensorSpec(shape=(25, 1), dtype=tf.int32, name='dense_2_target_30')]\n",
            "INFO:tensorflow:Overriding default placeholder.\n",
            "INFO:tensorflow:Cloning Adam {'lr': 0.0010000000474974513, 'beta_1': 0.8999999761581421, 'beta_2': 0.9990000128746033, 'decay': 0.0, 'epsilon': 1e-07, 'amsgrad': False}\n",
            "INFO:tensorflow:Remapping placeholder for input_3\n",
            "INFO:tensorflow:KerasCrossShard: <tensorflow.python.keras.optimizers.Adam object at 0x7fb517ee8a20> []\n",
            "INFO:tensorflow:Started compiling\n",
            "INFO:tensorflow:Finished compiling. Time elapsed: 379.7748966217041 secs\n",
            "5000/5000 [==============================] - 596s 119ms/sample - loss: 3.0650 - acc: 0.3426\n",
            "250/250 [==============================] - 2704s 11s/step - loss: 3.0758 - acc: 0.4616 - val_loss: 3.0650 - val_acc: 0.3426\n",
            "Epoch 2/100\n",
            "5000/5000 [==============================] - 2s 377us/sample - loss: 2.1450 - acc: 0.5480\n",
            "250/250 [==============================] - 33s 134ms/step - loss: 2.1236 - acc: 0.6020 - val_loss: 2.1450 - val_acc: 0.5480\n",
            "Epoch 3/100\n",
            "5000/5000 [==============================] - 2s 365us/sample - loss: 1.6572 - acc: 0.6694\n",
            "250/250 [==============================] - 34s 135ms/step - loss: 1.7307 - acc: 0.6659 - val_loss: 1.6572 - val_acc: 0.6694\n",
            "Epoch 4/100\n",
            "5000/5000 [==============================] - 2s 390us/sample - loss: 1.6133 - acc: 0.6492\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 1.5041 - acc: 0.7097 - val_loss: 1.6133 - val_acc: 0.6492\n",
            "Epoch 5/100\n",
            "5000/5000 [==============================] - 2s 400us/sample - loss: 1.5503 - acc: 0.6574\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 1.3462 - acc: 0.7441 - val_loss: 1.5503 - val_acc: 0.6574\n",
            "Epoch 6/100\n",
            "5000/5000 [==============================] - 2s 369us/sample - loss: 1.5742 - acc: 0.6538\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 1.2431 - acc: 0.7608 - val_loss: 1.5742 - val_acc: 0.6538\n",
            "Epoch 7/100\n",
            "5000/5000 [==============================] - 2s 374us/sample - loss: 1.2489 - acc: 0.7426\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 1.1522 - acc: 0.7808 - val_loss: 1.2489 - val_acc: 0.7426\n",
            "Epoch 8/100\n",
            "5000/5000 [==============================] - 2s 379us/sample - loss: 1.5116 - acc: 0.6726\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 1.0790 - acc: 0.7990 - val_loss: 1.5116 - val_acc: 0.6726\n",
            "Epoch 9/100\n",
            "5000/5000 [==============================] - 2s 384us/sample - loss: 1.3730 - acc: 0.6876\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 1.0314 - acc: 0.8056 - val_loss: 1.3730 - val_acc: 0.6876\n",
            "Epoch 10/100\n",
            "5000/5000 [==============================] - 2s 412us/sample - loss: 1.1546 - acc: 0.7506\n",
            "250/250 [==============================] - 35s 139ms/step - loss: 0.9797 - acc: 0.8167 - val_loss: 1.1546 - val_acc: 0.7506\n",
            "Epoch 11/100\n",
            "5000/5000 [==============================] - 2s 372us/sample - loss: 1.6578 - acc: 0.6334\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.9369 - acc: 0.8247 - val_loss: 1.6578 - val_acc: 0.6334\n",
            "Epoch 12/100\n",
            "5000/5000 [==============================] - 2s 383us/sample - loss: 1.8417 - acc: 0.5934\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.9042 - acc: 0.8314 - val_loss: 1.8417 - val_acc: 0.5934\n",
            "Epoch 13/100\n",
            "5000/5000 [==============================] - 2s 410us/sample - loss: 1.2933 - acc: 0.7200\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.8700 - acc: 0.8404 - val_loss: 1.2933 - val_acc: 0.7200\n",
            "Epoch 14/100\n",
            "5000/5000 [==============================] - 2s 372us/sample - loss: 1.3213 - acc: 0.7148\n",
            "250/250 [==============================] - 34s 135ms/step - loss: 0.8428 - acc: 0.8460 - val_loss: 1.3213 - val_acc: 0.7148\n",
            "Epoch 15/100\n",
            "5000/5000 [==============================] - 2s 376us/sample - loss: 1.1530 - acc: 0.7518\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.8179 - acc: 0.8495 - val_loss: 1.1530 - val_acc: 0.7518\n",
            "Epoch 16/100\n",
            "5000/5000 [==============================] - 2s 389us/sample - loss: 0.9725 - acc: 0.7960\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.7964 - acc: 0.8517 - val_loss: 0.9725 - val_acc: 0.7960\n",
            "Epoch 17/100\n",
            "5000/5000 [==============================] - 2s 355us/sample - loss: 1.0268 - acc: 0.7776\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.7738 - acc: 0.8588 - val_loss: 1.0268 - val_acc: 0.7776\n",
            "Epoch 18/100\n",
            "5000/5000 [==============================] - 2s 410us/sample - loss: 1.2832 - acc: 0.7132\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.7496 - acc: 0.8658 - val_loss: 1.2832 - val_acc: 0.7132\n",
            "Epoch 19/100\n",
            "5000/5000 [==============================] - 2s 375us/sample - loss: 1.1215 - acc: 0.7472\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.7350 - acc: 0.8671 - val_loss: 1.1215 - val_acc: 0.7472\n",
            "Epoch 20/100\n",
            "5000/5000 [==============================] - 2s 378us/sample - loss: 1.1233 - acc: 0.7522\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.7110 - acc: 0.8730 - val_loss: 1.1233 - val_acc: 0.7522\n",
            "Epoch 21/100\n",
            "5000/5000 [==============================] - 2s 394us/sample - loss: 0.9430 - acc: 0.7874\n",
            "250/250 [==============================] - 35s 139ms/step - loss: 0.6965 - acc: 0.8767 - val_loss: 0.9430 - val_acc: 0.7874\n",
            "Epoch 22/100\n",
            "5000/5000 [==============================] - 2s 373us/sample - loss: 1.0154 - acc: 0.7684\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.6846 - acc: 0.8781 - val_loss: 1.0154 - val_acc: 0.7684\n",
            "Epoch 23/100\n",
            "5000/5000 [==============================] - 2s 404us/sample - loss: 1.0144 - acc: 0.7652\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.6757 - acc: 0.8790 - val_loss: 1.0144 - val_acc: 0.7652\n",
            "Epoch 24/100\n",
            "5000/5000 [==============================] - 2s 366us/sample - loss: 0.9201 - acc: 0.7946\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.6596 - acc: 0.8842 - val_loss: 0.9201 - val_acc: 0.7946\n",
            "Epoch 25/100\n",
            "5000/5000 [==============================] - 2s 381us/sample - loss: 0.8389 - acc: 0.8246\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.6426 - acc: 0.8881 - val_loss: 0.8389 - val_acc: 0.8246\n",
            "Epoch 26/100\n",
            "5000/5000 [==============================] - 2s 369us/sample - loss: 0.7997 - acc: 0.8390\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.6356 - acc: 0.8898 - val_loss: 0.7997 - val_acc: 0.8390\n",
            "Epoch 27/100\n",
            "5000/5000 [==============================] - 2s 368us/sample - loss: 0.8901 - acc: 0.8248\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.6212 - acc: 0.8935 - val_loss: 0.8901 - val_acc: 0.8248\n",
            "Epoch 28/100\n",
            "5000/5000 [==============================] - 2s 396us/sample - loss: 0.9037 - acc: 0.8184\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.6152 - acc: 0.8929 - val_loss: 0.9037 - val_acc: 0.8184\n",
            "Epoch 29/100\n",
            "5000/5000 [==============================] - 2s 378us/sample - loss: 0.7747 - acc: 0.8490\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.5988 - acc: 0.8979 - val_loss: 0.7747 - val_acc: 0.8490\n",
            "Epoch 30/100\n",
            "5000/5000 [==============================] - 2s 384us/sample - loss: 0.8535 - acc: 0.8196\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.5936 - acc: 0.8996 - val_loss: 0.8535 - val_acc: 0.8196\n",
            "Epoch 31/100\n",
            "5000/5000 [==============================] - 2s 399us/sample - loss: 0.8223 - acc: 0.8384\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 0.5865 - acc: 0.8994 - val_loss: 0.8223 - val_acc: 0.8384\n",
            "Epoch 32/100\n",
            "5000/5000 [==============================] - 2s 393us/sample - loss: 1.0179 - acc: 0.7800\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.5791 - acc: 0.9027 - val_loss: 1.0179 - val_acc: 0.7800\n",
            "Epoch 33/100\n",
            "5000/5000 [==============================] - 2s 362us/sample - loss: 0.9320 - acc: 0.8116\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.5665 - acc: 0.9046 - val_loss: 0.9320 - val_acc: 0.8116\n",
            "Epoch 34/100\n",
            "5000/5000 [==============================] - 2s 415us/sample - loss: 1.1510 - acc: 0.7522\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 0.5673 - acc: 0.9048 - val_loss: 1.1510 - val_acc: 0.7522\n",
            "Epoch 35/100\n",
            "5000/5000 [==============================] - 2s 374us/sample - loss: 0.8525 - acc: 0.8180\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.5550 - acc: 0.9080 - val_loss: 0.8525 - val_acc: 0.8180\n",
            "Epoch 36/100\n",
            "5000/5000 [==============================] - 2s 357us/sample - loss: 1.0125 - acc: 0.7932\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.5580 - acc: 0.9056 - val_loss: 1.0125 - val_acc: 0.7932\n",
            "Epoch 37/100\n",
            "5000/5000 [==============================] - 2s 372us/sample - loss: 1.3693 - acc: 0.7074\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.5425 - acc: 0.9117 - val_loss: 1.3693 - val_acc: 0.7074\n",
            "Epoch 38/100\n",
            "5000/5000 [==============================] - 2s 383us/sample - loss: 0.7654 - acc: 0.8446\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.5352 - acc: 0.9110 - val_loss: 0.7654 - val_acc: 0.8446\n",
            "Epoch 39/100\n",
            "5000/5000 [==============================] - 2s 375us/sample - loss: 0.8809 - acc: 0.8008\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.5292 - acc: 0.9133 - val_loss: 0.8809 - val_acc: 0.8008\n",
            "Epoch 40/100\n",
            "5000/5000 [==============================] - 2s 402us/sample - loss: 0.6891 - acc: 0.8688\n",
            "250/250 [==============================] - 35s 139ms/step - loss: 0.5217 - acc: 0.9147 - val_loss: 0.6891 - val_acc: 0.8688\n",
            "Epoch 41/100\n",
            "5000/5000 [==============================] - 2s 369us/sample - loss: 0.8584 - acc: 0.8112\n",
            "250/250 [==============================] - 34s 135ms/step - loss: 0.5187 - acc: 0.9168 - val_loss: 0.8584 - val_acc: 0.8112\n",
            "Epoch 42/100\n",
            "5000/5000 [==============================] - 2s 410us/sample - loss: 0.7521 - acc: 0.8338\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.5119 - acc: 0.9187 - val_loss: 0.7521 - val_acc: 0.8338\n",
            "Epoch 43/100\n",
            "5000/5000 [==============================] - 2s 395us/sample - loss: 0.8058 - acc: 0.8326\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.5138 - acc: 0.9162 - val_loss: 0.8058 - val_acc: 0.8326\n",
            "Epoch 44/100\n",
            "5000/5000 [==============================] - 2s 387us/sample - loss: 1.1449 - acc: 0.7656\n",
            "250/250 [==============================] - 34s 135ms/step - loss: 0.5105 - acc: 0.9171 - val_loss: 1.1449 - val_acc: 0.7656\n",
            "Epoch 45/100\n",
            "5000/5000 [==============================] - 2s 356us/sample - loss: 0.6787 - acc: 0.8668\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.5012 - acc: 0.9199 - val_loss: 0.6787 - val_acc: 0.8668\n",
            "Epoch 46/100\n",
            "5000/5000 [==============================] - 2s 395us/sample - loss: 0.6806 - acc: 0.8692\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.4918 - acc: 0.9236 - val_loss: 0.6806 - val_acc: 0.8692\n",
            "Epoch 47/100\n",
            "5000/5000 [==============================] - 2s 387us/sample - loss: 0.7632 - acc: 0.8402\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 0.4971 - acc: 0.9196 - val_loss: 0.7632 - val_acc: 0.8402\n",
            "Epoch 48/100\n",
            "5000/5000 [==============================] - 2s 403us/sample - loss: 0.7454 - acc: 0.8476\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.4891 - acc: 0.9225 - val_loss: 0.7454 - val_acc: 0.8476\n",
            "Epoch 49/100\n",
            "5000/5000 [==============================] - 2s 396us/sample - loss: 0.7835 - acc: 0.8198\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 0.4866 - acc: 0.9227 - val_loss: 0.7835 - val_acc: 0.8198\n",
            "Epoch 50/100\n",
            "5000/5000 [==============================] - 2s 376us/sample - loss: 0.8104 - acc: 0.8300\n",
            "250/250 [==============================] - 34s 135ms/step - loss: 0.4777 - acc: 0.9265 - val_loss: 0.8104 - val_acc: 0.8300\n",
            "Epoch 51/100\n",
            "5000/5000 [==============================] - 2s 403us/sample - loss: 1.3374 - acc: 0.7258\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 0.4753 - acc: 0.9257 - val_loss: 1.3374 - val_acc: 0.7258\n",
            "Epoch 52/100\n",
            "5000/5000 [==============================] - 2s 357us/sample - loss: 0.9951 - acc: 0.8034\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.4778 - acc: 0.9248 - val_loss: 0.9951 - val_acc: 0.8034\n",
            "Epoch 53/100\n",
            "5000/5000 [==============================] - 2s 387us/sample - loss: 0.9778 - acc: 0.7846\n",
            "250/250 [==============================] - 34s 138ms/step - loss: 0.4680 - acc: 0.9276 - val_loss: 0.9778 - val_acc: 0.7846\n",
            "Epoch 54/100\n",
            "5000/5000 [==============================] - 2s 382us/sample - loss: 0.8371 - acc: 0.8254\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.4625 - acc: 0.9300 - val_loss: 0.8371 - val_acc: 0.8254\n",
            "Epoch 55/100\n",
            "5000/5000 [==============================] - 2s 386us/sample - loss: 0.7903 - acc: 0.8498\n",
            "250/250 [==============================] - 35s 138ms/step - loss: 0.4637 - acc: 0.9289 - val_loss: 0.7903 - val_acc: 0.8498\n",
            "Epoch 56/100\n",
            "5000/5000 [==============================] - 2s 371us/sample - loss: 0.7113 - acc: 0.8590\n",
            "250/250 [==============================] - 34s 136ms/step - loss: 0.4604 - acc: 0.9286 - val_loss: 0.7113 - val_acc: 0.8590\n",
            "Epoch 57/100\n",
            "5000/5000 [==============================] - 2s 361us/sample - loss: 0.6660 - acc: 0.8650\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.4627 - acc: 0.9281 - val_loss: 0.6660 - val_acc: 0.8650\n",
            "Epoch 58/100\n",
            "5000/5000 [==============================] - 2s 382us/sample - loss: 0.7407 - acc: 0.8456\n",
            "250/250 [==============================] - 35s 139ms/step - loss: 0.4519 - acc: 0.9317 - val_loss: 0.7407 - val_acc: 0.8456\n",
            "Epoch 59/100\n",
            "5000/5000 [==============================] - 2s 349us/sample - loss: 0.8116 - acc: 0.8342\n",
            "250/250 [==============================] - 34s 137ms/step - loss: 0.4507 - acc: 0.9328 - val_loss: 0.8116 - val_acc: 0.8342\n",
            "Epoch 60/100\n",
            "5000/5000 [==============================] - 2s 358us/sample - loss: 0.7372 - acc: 0.8612\n",
            "250/250 [==============================] - 35s 140ms/step - loss: 0.4499 - acc: 0.9330 - val_loss: 0.7372 - val_acc: 0.8612\n",
            "Epoch 61/100\n",
            "5000/5000 [==============================] - 2s 409us/sample - loss: 0.7949 - acc: 0.8296\n",
            "250/250 [==============================] - 35s 139ms/step - loss: 0.4444 - acc: 0.9337 - val_loss: 0.7949 - val_acc: 0.8296\n",
            "Epoch 62/100\n",
            "174/250 [===================>..........] - ETA: 9s - loss: 0.4422 - acc: 0.9332"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QG-vhJ14RkBy",
        "colab_type": "text"
      },
      "source": [
        "# Visualization of confusion matrix\n",
        "\n",
        "The below code takes a confusion matrix and produces a nice and shiny visualization"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "UiKRYOWPfhJs",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def plot_confusion_matrix(cm, classes,\n",
        "                          normalize=False,\n",
        "                          title='Confusion matrix',\n",
        "                          cmap=plt.cm.Blues):\n",
        "    \"\"\"\n",
        "    This function prints and plots the confusion matrix.\n",
        "    Normalization can be applied by setting `normalize=True`.\n",
        "    \"\"\"\n",
        "    if normalize:\n",
        "        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
        "        print(\"Normalized confusion matrix\")\n",
        "    else:\n",
        "        print('Confusion matrix, without normalization')\n",
        "\n",
        "    print(cm)\n",
        "\n",
        "    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n",
        "    plt.title(title)\n",
        "    plt.colorbar()\n",
        "    tick_marks = np.arange(len(classes))\n",
        "    plt.xticks(tick_marks, classes, rotation=45)\n",
        "    plt.yticks(tick_marks, classes)\n",
        "\n",
        "    fmt = '.2f' if normalize else 'd'\n",
        "    thresh = cm.max() / 2.\n",
        "    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n",
        "        plt.text(j, i, format(cm[i, j], fmt),\n",
        "                 horizontalalignment=\"center\",\n",
        "                 color=\"white\" if cm[i, j] > thresh else \"black\")\n",
        "\n",
        "    plt.ylabel('True label')\n",
        "    plt.xlabel('Predicted label')\n",
        "    plt.tight_layout()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BqY-vngiRoTZ",
        "colab_type": "code",
        "outputId": "cb03871a-d4a8-4fd1-b3eb-1bf4c510cbff",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 801
        }
      },
      "source": [
        "results = resnet_model.predict(x_test, batch_size=hparams.test_batch_size)\n",
        "\n",
        "# convert from class probabilities to actual class predictions\n",
        "predicted_classes = np.argmax(results, axis=1)\n",
        "\n",
        "# Names of predicted classes\n",
        "class_names = [\"airplane\", \"automobile\", \"bird\", \"cat\", \"deer\", \"dog\", \"frog\", \"horse\", \"ship\", \"truck\"]\n",
        "\n",
        "# Generate the confusion matrix\n",
        "cnf_matrix = confusion_matrix(y_test, predicted_classes)\n",
        "\n",
        "# Plot non-normalized confusion matrix\n",
        "plt.figure()\n",
        "plot_confusion_matrix(cnf_matrix, classes=class_names,\n",
        "                      title='Confusion matrix, without normalization')\n",
        "\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "INFO:tensorflow:New input shapes; (re-)compiling: mode=infer (# of cores 8), [TensorSpec(shape=(4, 32, 32, 3), dtype=tf.float32, name='input_1_10')]\n",
            "INFO:tensorflow:Overriding default placeholder.\n",
            "INFO:tensorflow:Cloning Adam {'lr': 0.0010000000474974513, 'beta_1': 0.8999999761581421, 'beta_2': 0.9990000128746033, 'decay': 0.0, 'epsilon': 1e-07, 'amsgrad': False}\n",
            "INFO:tensorflow:Remapping placeholder for input_1\n",
            "INFO:tensorflow:Started compiling\n",
            "INFO:tensorflow:Finished compiling. Time elapsed: 252.44182968139648 secs\n",
            "INFO:tensorflow:New input shapes; (re-)compiling: mode=infer (# of cores 8), [TensorSpec(shape=(1, 32, 32, 3), dtype=tf.float32, name='input_1_10')]\n",
            "INFO:tensorflow:Overriding default placeholder.\n",
            "INFO:tensorflow:Remapping placeholder for input_1\n",
            "INFO:tensorflow:Started compiling\n",
            "INFO:tensorflow:Finished compiling. Time elapsed: 136.7031545639038 secs\n",
            "Confusion matrix, without normalization\n",
            "[[410   4   3   0   7   0   3   1  33  27]\n",
            " [  4 469   0   0   0   0   0   0   2  30]\n",
            " [ 23   0 384  12  41   7  16   4   6  19]\n",
            " [  4   0   5 348  40  36  23   8   9  24]\n",
            " [  0   1   1   3 490   1   8   3   0   0]\n",
            " [  4   1   5  34  26 382   8   8   1  19]\n",
            " [  3   1   6   8   8   3 458   0   1   3]\n",
            " [  9   1   1   6  15   3   3 437   2  18]\n",
            " [ 11   1   2   0   1   0   1   0 473  15]\n",
            " [  3   8   1   0   0   0   0   0   5 496]]\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAboAAAGACAYAAADbFqdOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3XdYFEcfwPHv0auoKFgxoiKoiGLB\nLiAIqAQbigV77yWxm8QeNcbYo8bYE/OqWLCLiFGDxq4gijWKBUEpwgFS9v2DeIIVjjsQMh+fe+T2\nduY3s3t3czNbRiZJkoQgCIIgFFEaBV0AQRAEQVAn0dAJgiAIRZpo6ARBEIQiTTR0giAIQpEmGjpB\nEAShSBMNnSAIglCkiYZOEARBKNJEQ1eESZLE+vXradeuHW5ubri4uPDdd9/x8uXLPOX71Vdf0bJl\nS06ePJnrtFevXqV///55iq9qBw4cICEh4b2vLVq0iN9//11tsSdMmEBgYOA75Zg0aRIrV65UWZy7\nd+9y7tw5leWnDr6+vuzZs4fIyEjatWundD5Z63r06FEmT56sqiIKhZRWQRdAUJ8ffviBv//+m3Xr\n1mFubo5cLmfOnDkMHjyYrVu3IpPJlMp3//79HD58GAsLi1ynrV27NuvWrVMqrrosXboUe3t7jIyM\n3nlt/Pjxao29YMGCHJUjrwICAkhLS6NBgwYqz1vVzM3N2bdvn9Lps9bV1dUVV1dXFZZOKIxEj66I\nio2NZfPmzXz//feYm5sDYGBgwDfffMOAAQOQJImUlBS++eYb3Nzc8PDw4Pvvvyc9PR0AZ2dntm3b\nRufOnWnWrBnff/89kPmrOyMjg/79+3PixAmcnZ05f/68Iu7r52lpaUydOhU3NzdcXV0ZMWIECQkJ\nnD17VvHFo0z8t/n6+rJmzRq6du1Ko0aN2Lp1KytXrsTd3Z02bdrw8OFDIPNXfrdu3fDw8MDV1VXx\nRTp58mTu3buHr68v58+fZ9KkScybNw9PT08OHjyo6FldvXoVR0dHEhMTAfj5558ZNWrUB7d/cnIy\ndevWJTk5GYA1a9bQvHlzxeuzZ89m/fr1il7M2+UAiIuLY+DAgTg6OtK/f39Fb+/GjRv4+Pjg7u6O\nl5eXomft5+dHnz59FDFePw8MDGT16tVs2rTpvdvxY9v64MGDtGvXDnd3d3r16sWDBw8AWLZsGdOm\nTaNz585s2LABPz8/Ro0axfjx43F0dKRv376cP38eHx8fmjRpwh9//AFARkYGM2bMwM3NDWdnZ77+\n+mtSU1OzlSciIoIaNWoAmT803N3dcXd3x9nZmerVq5OQkPDBfN6ua9ZtEhsby+jRo3Fzc6NNmzas\nWbNGEbN69ers3r2b9u3b06xZMzZs2PDBfSsUQpJQJAUFBUmurq4fXWf16tXSwIEDpdTUVCkpKUnq\n1KmTtHv3bkmSJMnJyUkaN26clJaWJj19+lSqWbOm9OTJE0mSJMnKykrxt5OTk3Tu3DlFnq+fHz9+\nXOrVq5eUkZEhZWRkSIsXL5b+/PNP6cyZM5KLi0ue4mfVs2dPacCAAVJqaqoUGBgo2dnZSTt37pQk\nSZJGjhwpLV68WJIkSRo8eLC0evVqSZIk6e+//5Zq164tvXr16p36TJw4UfL09JSSk5MVz1esWCFJ\nkiTNmjVLWrRokfT06VOpefPmUmRk5Ee3b/fu3RXbZtCgQZK3t7f08OFDSZIkycvLSwoLC5N69uyp\nqPPb5Wjbtq0UExMjpaamSl5eXtKuXbuk9PR0ycPDQ/L395ckSZKuXr0qNWjQQHr58qW0c+dOqXfv\n3or4WZ9nrcfbPrStHz16JNWrV0+6f/++JEmStG7dOkV+S5culZo1ayY9f/5cEatOnTrS3bt3pZSU\nFKl58+bS4MGDpbS0NCkwMFBq0aKFJEmSdOjQIaldu3bSq1evpOTkZMnDw0NR/9fb4uHDh5KNjc07\n5Zw6dao0a9asT+aTta5Zt8H06dOl6dOnS5IkSTExMZKjo6Ni/1hZWUkLFy6UJEmSrly5Itna2kpp\naWkf3b9C4SF6dEVUbGwspqamH10nKCiILl26oKWlhZ6eHp6enpw+fVrxuqenJ5qampibm2NqasqT\nJ09yHL9kyZLcuXOHo0ePkpSUxJgxY7L1aFQZ38nJCS0tLaysrEhKSsLNzQ0AKysrnj17BsDKlSsV\nxwbr1atHSkoKUVFR782vcePG6OrqvrN87NixHDp0iMmTJzNs2DDMzMw+ug0cHBy4dOkSGRkZPH78\nGCcnJy5evEhCQgJRUVFUr179o+lbtGhB8eLF0dLSolq1akRGRhIREUF0dDRt27YFwNbWlnLlynHt\n2rWP5vUp79vWp0+fxsHBgUqVKgHg7e3N2bNnSUtLA8DOzo6SJUsq8qhatSqVK1dGR0eHSpUq0axZ\nMzQ1NbPtBzc3N3bu3Im2tja6urrY2toqet0fc+jQIa5du8aECROUzufEiRN0794dgOLFi+Pq6prt\n/ebl5QVAzZo1SUlJ4fnz5zndfMJnTjR0RVSJEiWIjIz86DovXrzAxMRE8dzExCTbhzvrsSJNTU3F\nsGJO1K5dm2nTprF582aaNm3K+PHjiY+PV0t8Q0NDxTpZn2toaJCRkQHAyZMn6dGjh2LYSpIkxWtv\ny1qmt+N4eHhw4cIFPD09P1p/yGzoLl++zM2bN6lSpQp16tTh4sWLXLx4kQYNGnzyGOn76v/ixQuM\njY2zpS1WrBgvXrz4ZHlyGysmJoZixYoplhsbGyNJEjExMcC72+n1dn+dh4GBgeLv19v6xYsXTJw4\nETc3N9zd3Tl27BjSJ+4r/+jRI+bOncuPP/6Ijo6O0vm8ePEiW32KFSuW7f1mbGysKC/wwfeHUPiI\nhq6IqlOnDs+fPyc0NDTb8tTUVBYvXkxSUhKlSpUiNjZW8VpsbCylSpXKVZysjQlkHld6zd3dnc2b\nN3P8+HGSkpLeOQlFFfFzIjU1lTFjxjB06FAOHz7M3r17lToRJzIyEn9/f9q2bcvy5cs/uX7dunUJ\nCwvj/Pnz2NvbU7t2ba5evcqFCxdo3LixMlXB1NSUuLi4bF/qr3vvGhoa2X4MvP3DQplYWfdPXFwc\nGhoalChRQuk8Fy9ejJaWFv7+/hw6dIiWLVt+dP309HTGjx/PyJEjqVKlitL5QP6934TPj2joiqhi\nxYoxYMAAJk6cyD///ANAUlIS33zzDdevX0dfXx9HR0d27NhBeno6crmcPXv25OgLI6vSpUtz48YN\nIPP0+JSUFAB27tzJihUrgMxhIktLy3fSqiJ+TiQlJSGXy6lVqxYAGzduRFtbG7lcDoCWllaOGoU5\nc+YwYMAApkyZwsGDBwkLC/vo+jo6OlSoUAF/f3/s7e0xNDREJpNx6tSp9zZ0OSlHhQoVKFOmDAcO\nHADg4sWLREdHU7t2bczMzLh37x4pKSkkJSVx6NChbHnn9rKSpk2bcv78ecWQ4LZt22jatClaWsqf\nrP38+XOsrKzQ0dHhxo0bXLp0SbEf3mfZsmWUKVMGb2/vHOfzobo6OjoqTop58eIFR48exdHRUem6\nCIWHaOiKsJEjR9KlSxeGDh2Km5sbHTt2xNTUVNEb8fX1pUyZMrRt25ZOnTrh6OiIh4dHrmIMGzaM\nDRs20K5dO+7cuUPVqlUBaNWqFaGhobRu3RoPDw9u375N3759s6VVRfyceN3ot2/fnvbt22NhYYGL\niwtDhgxBLpfj7u6Oj4+PovF4n6CgICIiIvDx8cHIyIixY8cybdo00tPTP3qtnYODA7du3cLa2hrI\nHNKNiYl576UZOSmHTCbjxx9/ZMuWLXh4eDB79myWLFmCgYEBDg4O2NnZ4ebmxsCBA2nVqpUinZOT\nE9u2bfvomaJvK1OmDLNnz2bYsGG4u7tz7tw5Zs6cmeP079OvXz+2bduGh4cHW7duZeLEiWzfvp2D\nBw++d/3Vq1dz5coVxZmX7u7unD9//qP5fKiuY8aMIT4+Hnd3d3r27MmgQYOoXbt2nuojFA4y6VMD\n24IgfNTFixcJDQ3F19e3oIsiCMJ7iB6dIORRSkoK7u7uBV0MQRA+QPToBEEQhCJN9OgEQRCEIk00\ndIIgCEKRJm7qrISSvX5TOu3puW1oOuXDZ9V9SMQv3ZSOqacFyWnKpVXyvs/oakGK0jGVC6qjCa9y\nfk17NukZyo/g62tBkhJ11dRQcuOSt7oqe7SisO3T+KTUT6/0ASUNtHghV66yyu5XE31N4pKUq6yp\nYf58levXHaF02qRLn772VF1EQ5fPbCoUz/eYGhoyIH8PxWrICiJmvoZ7E7dAtm++hvs35n+jngBa\nmvkfWKugKpsbssI5CFg4Sy0IgiAIOSR6dIIgCELOKHsso4CJhk4QBEHImUI6dCkaOkEQBCFnCmmP\nrnA2z585V7tyvNjUnYqlMqct+cLMiOMz3fGb6JxtvWIG2mwc1Zy/F7Tj9Nw2tG/47v0PVWH//v0Y\n6mrwz/37ask/q91+O3GoXxdra2taOTYnNCRE7TGDjgfSuIE9VlZWtHV3JSIiQu0xd/ntoK6tDXVt\nbbC2tqaurQ1Guhq5vnFybhVEXQtin0LmrBPjx49HX1umtnru2+OHc9P6NK1XC8/WjoRdz6zbt99+\nS9N6tWhctwYD+3QnLsusB6pwcL8/jo3r0djelrauLQkLDWHChAk0qltL8bCztsS5WUOVxs0zmYby\njwIkGjoV09fR5NsudXiRkHkX/6pljNk2riWX7r47ieO3Xerw6HkiDSfsw3vhceb3qk/ZEvoqLY9c\nLmfSpEnZJshUl4cPHjBqxFC279zNjRs36NipM0MG9VdrzMTERHr18GHl6l8IDw+nTVtPRg0fotaY\nAB06dubStTAuXQvjxo0bTPt2Bl+276iY00wdCqKuBbFPX/Pu6JVtnjxVi3j4gAljRrDx952cvhCC\nZ/tOjBk2CL/t2zh69CgBp85x+kIIGenpLFn0vcriPnn8iBGD+7H6180EX7xGJ28fxo8exoIFCzhz\nKUTxaO3ehm49eqksrkrIZMo/CpBo6FRsYgdb/jh9j4R/r+FJTk3Ha94xzt2Ofmddr4YWrA+8DcDj\nmCROh0XiXre8SsszZ9Z3+Pr6YqTGL+DXtLS1Wb9pKxb/zkjt6NSKW+E31Roz6HggX1S2pK69PQC9\n+/Yj4OgRtfesskpOTmbWt9OZPXe+WuMURF0LYp++NmnKdGbMmKG2/LW1tVm1bhMVLTLr1tzRiTu3\nw6lubcOqVavQ19dHQ0ODJs1acvtWuMriamlps2b9Fqrb1ADAoUlTboRdz7ZOWGgIf506Sd+B6v/R\nliuiRyfYVDDBsVYZVh2+oVgW8VxOZFzyO+uWMNKhpJEu9569+ZK69ywBq7Lvn91aGSEh1wg8FsDY\nsWNVlufHlC1bllYurgCkpaWxZfMG2nl6qTXmrVvhWFq+mZDTyMgIU1NT7ty+rda4Wa1bt45GTZpi\nmWViUHUoiLoWxD59rZGSk9PmlHmZsrR0dgEy6/bH1s24t/Gkpq0ddnZ2AMTHxeG/eydubT49o3xO\nlTYzo5Wrm+L5sSOHqVc/+xDlwnmzGTl2fJ7m/lML0aMTfuzTkImbL5CW/umLag10tEjPyMi2bvKr\ndAx0NVVSFkmSGD1iKIsWL0VbW1sleebUimVLMDc35/SpU8yaq7ohn/dJksvR09PLtkxPX5/ExES1\nxn0tIyODRYsWMWrseLXHKsi65uc+zW9rVi6jVpUKnPnrFNNnzlUsH9LPl9pWFnxhWYUu3XqqJfaf\nxwP5efkSZn//g2LZ3Tu3OX/uLJ26KH83JCG7z76hGzt2LMnJ7/aI3sfZ2TnfvuDe1tupKjcfx3E2\nPCpH6yempKGpoYG25ptdoK+rSaKy91h6y6+/rMHaxoYmTZupJL/cGD5yNNHR0YwYORrnlk1JSkpS\nWywDA8N33h9Jcrlaj+1kdfZMMEZGRtSoUVPtsQqyrvm5T/PboGEjCbv/hEHDRtLWtaWibj//upkb\n/0RiYGDIsIG9VR73gP8eRgzpz9YduxXDmAC7d26nradXvv9AzRExdKkeixcvfudX7OeojX0FPOwr\nELa0A2FLO1De1IBj37nRzMbsvevHJr4iKj6ZyuZvvqSqmBtz81GcSsqzz38v+/z3UtmiLGXKlCHi\n4UNaNG3IiaDjKsn/fW6EhRF4LADIvLdhF59uvIyPJ/ym+o7pVLe25s6dN0N3cXFxxMTEULVaNbXF\nzOrQgX20adMmX2IVRF0LYp/ml/CbYZw4fgzIrFtHbx8S4uPZuG41oaGhAOjp6dGzTz+Cjh1VaewT\nx48xZcI4duw5QF37+tleO3JoPy5uHiqNpzKFdOjysxoATkhIYPz48cjlcpKTk5k+fTpjxozB39+f\nWbNmoa2tTWxsLE5OTpw8eZKEhASePn1Knz596NSpkyKfGzduMGPGDLS0tNDQ0GDJkiUkJCQwadIk\nKlasyM2bN7GxsWHOnDlERkYydepUUlNT0dTUZPbs2ZQrVy7XZe+6KCjb88uLvsRz3jEeRn+4h7n7\n7AOGtK7OuA3nqF6uGE2szfhq4/lcx36fXXv3K/420JFR6YsvOHTkOJW++EIl+b9PdHQUA/r15lTw\nOapUKk/wX6dJTU2lsqWl2mK2dHRiyMB+nD51ilaOzVi2ZDEebdthaGiotphZXbt6le7duuZLrIKo\na0Hs0/zyPDqakYP7ceREMGXKluPvM3+RmpZKYkIC48aN45etO9HV1eXIwf3UqGmrsrhyuZyRQwaw\nadsOrKxt3nn9esg1rKpbqyyeSokLxvMuKioKb29vXFxcCA4OZu3atdleNzExYdasWfj5+XH79m12\n7dpFfHw8Xl5edOjQQbHe8+fPmT59OjVq1GDJkiX4+/vj5OREaGgoixcvxtTUlBYtWhAfH8+SJUvo\n168fTZo04cSJE6xcuZLZs2d/tJyn57bJ0c2Zr/z4/oP2LzZ1z/a8j/ObX+Q3l3f8ZL7KkAH6OjIM\ndNT3y8rVuSXTpk7F08OVjIwMdHV12bZtG+amqjvB5m16xvps27aN0aOHk5iYSNWqVdmwYQN6uX5n\nK7ddnjyOoEyZMhiqcbu+VhB1LYh9ChAZGUnLli0Vz91dHNHS0uLYsWOUL5+zM5P1jD8+9Ofl7kzE\ntKn4tPdQ1O2PbdtwdnZm7NixuDSthyRJVKxYkY3r12H2ifxy6sje/TyPjmL4gOzDoSdOnEBbWxu5\nXI6NZQV0dXO2Y58nquZwR44U0gvGP6uGrlSpUqxcuZJ169bx6tUrDAwMsr1eu3Ztxd8NGjRAS0uL\nkiVLYmJiQkxMjOI1U1NTfvjhB5KTk3n27BmenplnTFlYWFC6dGkAzMzMePnyJZcuXeLevXusWrWK\n9PT0HF1vpsw0O6+92NRdqWl+8jJNj4GOjOvh9wCQv8rd3edz+77uN2gY/QYNQ19bRlJqZqzX/+c8\nZu6CNmrmyNkLV7JNR5TbaYmUnaYn+PwVDHVkJOZyu4Jy07mooq65naanIPapiak5l0NuvHeKqZzW\nNyfT9Hj3GoR3r0HZ06XCqlWrePYye/q3n3/Ip/Zr6y+9efTc+53lpoZaPE9MIzohlYQ0SEjLxwYs\np0SPLu82btyIubk5Cxcu5Nq1ayxYsCDb61kPzmZkZCj+liQp2wdpzpw5DBw4kBYtWrBu3TrkcjkA\nmprZz2iUJAltbW2WLFmCmdn7j6UJgiAI/yqkDd1nVeqYmBgsLDJvgxUQEEBq6od/QV2+fJn09HRe\nvHhBYmIixYu/GUqMjY3FwsKCV69eceLEiY/mY2dnR0BA5sH24OBg/P39VVQbQRCEIkZDpvyjIItd\noNHf4uXlxfr16+nXrx+1a9cmKirqg8Ms5cuXZ/To0fTu3ZsxY8agofGmKj179mT48OGMGjUKX19f\ndu3aRUJCwnvzGTFiBMeOHaNHjx6sWLGCOnXqqKVugiAIQsGQSbkdsP8M+Pn5cevWLSZOnFgg8ZU5\nxvZaQR2jy+2xudeUPfac9XhO7mMqF/R9x3NyStljdEC+HqN7LS91VfYjX9j2aU6O0X2ImbF2jo/J\nvU3Z/fr6GJ2yafODvvMcpdMmBU5VYUly57M6RicIgiB8xsRZl/mnY0f1nIIvCIIgfEQhPRmlUDZ0\ngiAIQgEQPTpBEAShSBM9OkEQBKFIEz06QRAEoUgrpD26wllqQRAEQcgh0aMTBEEQckYMXf535OXi\nbWXTm7p8p3S8pD9nKJ0+JnCG0nGVvUi4IOTl4m1VpM9PedkvhWmfGud+WgeVpE9MSVc65md/+45C\nOnQpGjpBEAQhZwrRD52sREMnCIIg5Izo0QmCIAhFmmjoBEEQhCJNDF0KgiAIRZro0QmCIAhFWiHt\n0RXO5rkQ279/P4a6Gvxz/75K83VvVI2kP2dgUSZzpvUvm1tz7bdRXN82GgBjA10ALMuX5MDi3lz7\nbRRnfx2KXbUyKi1H0PFAGjewx8rKirburkRERKg0/88lZkHFFTHVa5//Xhzq18XGxoZWjs0JDQlR\nSxz/PX44NqlHY/tatHVtSdj1zDg/r1hCk3q2NKpbkzHDB/Hq1Su1xP+vEQ1dPpLL5UyaNImSJUuq\nNF99XW1mDXHleZwcgEpli/PTuHZ4fb2FGj5LAGjTxAqADdM7sfdkGLbdlzJ11RG2zOiisnIkJibS\nq4cPK1f/Qnh4OG3aejJq+BCV5f+5xCyouCKmej169IhB/fuwYdNWwsLC6OLTjZFqiBvx8AFfjx7O\n5m1+BF8M4csOnRg9bCBnzpxh7arlHDx2kuCLIcTFxbF21XKVx88TmYbyjwIkGrp8NGfWd/j6+mJk\nbKzSfKf1deT3w1dIkKcA0M3Vjj0nrnP30QvFOn8EXMPYQJcGNSqw6cAlAALO3SE1LZ3aVVXTqws6\nHsgXlS2pa28PQO++/Qg4eoSXL1+qJP/PJWZBxRUx1btPtbW12bD5N2xq1ACgSZNmhF0PVXkcLW1t\nfv51MxUtKgHQwtGZ27fC2b59O14dvTEpXhyZTEZ33z7s3b1D5fHzRCZT/lGAREOXT0JCrhF4LICx\nY8eqNN+almY416/C0v8FK5bVrmrOq9R09i3qxdWtI4HMXp/0720XNLK86RKTXlGlvGp6mLduhWNp\nWUXx3MjICFNTU+7cvq2S/D+XmAUVV8RU7z41MzOjtZu74vmRwwdp0NBB5XHKlCmLo7MLAGlpaWzb\nsgmPtp6Eh4dTubKlYr3KlS25FX5T5fHzQiaTKf0oSKKhyweSJDF6xFAWLV6Ktra2SvNeNt6T8UsO\nkJaeoVhmYqSHc4Mq9J21k0b9fwZggm9zEpJe8XfoQ0Z1bQKAUz1LalQ2Q1dHNeckJcnl6OnpZVum\np69PYmKiSvL/XGIWVFwRU737NKtjx46xbOlPzF/4o9pirF65lBqW5TkTfIrpM+chl8vRzVJvPX19\n5PlY55wQDV0eHD58WOV5nj17llGjRr2zfM6cOTx8+JBly5axZcsWlcd9n19/WYO1jQ1NmjZTab79\nv6xP2P0o/rr2INvy+MQU/E/eICo2EXlyKgAuDTJ/IfeZtZPGthW5unUknZxq8te1B8QlJKukPAYG\nhiQnZ88rSS7HyMhIJfl/LjELKq6Iqd59+trePbvp06cPO3f7K4Yx1WHwsFHc/Ocpg4eNoq1LCzQ0\nNEjJUu8kuRzDfKpzjsny8ChABd7QRUREsH///nyLN3XqVCpWrJhv8SDzTK59/nupbFGWMmXKEPHw\nIS2aNuRE0PE85duuWXXaNavOvV1fcW/XV1QwM+HUmkF8UbYEJoa62dZNT88ctrz3OAbP8Zup3WMZ\nI37wx7JcSULvRuapHK9Vt7bmzp03w0txcXHExMRQtVo1leT/ucQsqLgipnr3KUDgsQC+Hj+GI0eO\nUK9efbXECL8Rxonjx4DMHlJHbx9exscjk8m4d/eOYr27d25TvbqNWsqgLNGje0tCQgKDBw/G19cX\nb29vrl69irOzs2L4Yf78+fj5+TFz5kz+/vtvli9fzsuXLxk+fDi+vr5069aN0NDMA8EuLi7MnTsX\nT09PFixYwPz58/nyyy/54YcfALh58yY9evTA19eXIUOGEBsbC2R+QIYPH0779u1ZsWIFAL6+voSH\nh2cr6+LFi+nRowc+Pj7s27dP5dti1979/BMRyb0HT3j69CkVKlbkz9N/09LRKU/5dpiwlUpeC6nc\n4Qcqd/iBiGdxNBu0htE/7qOTcy3Kly6Gxr931Q+8cBeA7fO60b5l5oenW+vaPIyM40FkXN4q+K+W\njk48fPAPp0+dAmDZksV4tG2HoaGhSvL/XGIWVFwRU737VC6XM3hgP37/305sbNTXwERHRzN8UF+e\nPnkMwNng06SmpTJt2jT8dvzBs2eRpKWlsWbVMjp4d1VbOZRRWBs6tV0wHhUVhbe3Ny4uLgQHB7N2\n7dr3rte/f3+2bt3KiBEjWL58OXZ2dgwaNIhr164xb948tmzZQkREBF27dmXs2LE0bNiQLVu2MHr0\naJycnPjqq6+YM2cOEyZMwM7OjnXr1rFp0yYcHBy4efMmx44dQ1tbG3d3d3r06PFO/PPnz/Po0SO2\nbt3Kq1ev6NChAy4uLu8cIyhM/r4ewZz1QRxb3o/Uf4/d/bD1JAA/bj3F8q+/ZO7Q1jx4GseAuX4q\ni6uvr8+mrdsYO2o4cnkillWqsmbdBpXl/7nELKi4IqZ67du7h+ioKPr16olM9mbKnMPHgjA3N1dZ\nnCbNmjP260l08nQnIyMDXV0d1qzfSosWLRg2aiyerZ2QkHB0akXfAeq/rOK/QCZJ6pkB6eXLl8yc\nOZOIiAhevXqFgYEBjx49wt/fH0NDQ+bPn0+1atUoX748W7duZenSpQwZMoShQ4diZ2cHQPPmzTl5\n8iT169fn/PnzADg4OHD69Gm0tLRwcHDg7NmzNG3alNOnTwMQEhLC8uXL6du3L2vXruWXX34BYODA\ngYwaNYoFCxYwffp0Dh8+TIkSJZDL5Wzfvp0yZTJPsY+OjmbNmjUfHd7MyJAUPSVBEISCFJ2QRimj\n/LnJVTGfTUqnjd/WS4UlyR21bZ2NGzdibm7OwoULuXbtGgsWLMj2empq6jtpZDIZWdvdjIzM3oim\npma29bS0Plzs1NRUNDQ0FPnBono4AAAgAElEQVS9nf/bdHR06Ny5M4MHD/5Ejd5ITgNQ7veBgY4M\n+avcp83rxKv6Lb5VKq2yE6/qab3eTvmnIGIWVFwR89Py8hteX1tGUqpy6ZWdeLWUkRbRCQXwBs6F\ngh6CVJbajtHFxMRgYWEBQEBAAKmpqRgZGREVFUV6ejpXrlzJLICGBmlpmTvX1taWs2fPAnD58mWq\n5fDgc7Vq1bh0KfMi6HPnzlGrVi0Arl+/TlJSEikpKdy5c0dRnqxq167N8ePHycjIICUlhVmzZuWt\n4oIgCEVVIT3rUm09Oi8vLyZOnMihQ4fo0aMH+/btY/DgwQwZMoTKlStTtWpVAKpUqcL169eZO3cu\no0aNYsqUKfTq1QtJkvjmm29yFGvatGnMmDEDmUyGiYkJ8+bNIzQ0lBo1ajBlyhTu37+Pj48PxYoV\neyetvb09Dg4OdO3aFUmS6N69u0q3gyAIQlFRWHt0ajtGV5QpM/T4mhi6VB8xdCliZvVfGrrMr2N0\nJXpuVTptzJZ3TwbML2KaHkEQBCFHCmuPTjR0giAIQo4U1oauwO+MIgiCIAjqJHp0giAIQs4Uzg6d\n6NEJgiAIOaPuW4AlJyfj4uKCn58fT548wdfXl+7duzN69GjFbOt79+6lU6dOeHt7s3379hzlKxo6\nQRAEIUfU3dCtWrUKExMTAJYuXUr37t357bffqFSpEjt27EAul7NixQo2bNjA5s2b2bhxo+Lexh8j\nGjpBEAQhR9TZ0N25c4fbt2/j6OgIZE611qpVKwCcnJwIDg7mypUr2NraYmxsjJ6eHvb29ly8ePGT\neYuGThAEQcgZNd4ZZf78+UyaNEnxPCkpCR0dHQBMTU2JiooiOjqakiVLKtYpWbIkUVFRn8xbnIwi\nCIIg5Ii6Li/YvXs3derU+eDN9D908X9ObwogGjolpKRlKJ3WQEdTqfTK3qEkr+mrjt6tVLqIFe2V\nThu26Eul0ulpaZCq5L5JSFH+lh9lTXSISXyV63TF9LWVjgky0jOUu3NHWrpy20hPS5OUVOXu+qGt\nqezgkYwMJeuZ11s+KRkWLU3lG4O8pM0P6mrogoKCePjwIUFBQTx9+hQdHR0MDAxITk5GT0+PyMhI\nzMzMMDMzIzo6WpHu2bNn1KlT55P5i4ZOEARBKFA//fST4u9ly5ZRvnx5Ll26xOHDh/Hy8uLIkSM0\nb94cOzs7pk2bRnx8PJqamly8eJEpU6Z8Mn/R0AmCIAg5kp93Rhk5ciQTJ07kjz/+oFy5crRv3x5t\nbW3Gjx9P//79kclkDB8+HGNj40/mJRo6QRAEIUfyo6EbOXKk4u/169e/87q7uzvu7u65ylM0dIIg\nCELOfN6HED9INHSCIAhCjoibOgvZHNzvT4tG9XCwr4WHSwuuh4YA8O233+JQtyYN7Gzo16sbcTm4\nql9ZQccDadzAHisrK9q6uxIREaGyvNvUKcfhyU4ETW+F37jmVC9rjIYMvutky4lvMi/yXNSzLga6\nmtnS6etoEjyzNePaWOcpfmpqKlMmfkUxfU0eZanX/HmzqWdXg7q21vTp6UNcXFye4rxPwOEDlCuu\ny8N/7gOZF7q2buFAF6/cDafk1i6/HdS1taGurQ3W1tbUtbXBSFeDly9fqjxWamoqUyd9RXEDrWzb\nN/ivUzSub0edmlZ4erjw5PFjlcfOav/+/RjqavDP/ftqjfPak8eP8fRozRdffIFDPTtOnfxTLXFS\nU1OZNukrSmTZvmlpaUyb9BUN69TEtrolSxf/oJbYeaHuO6Ooi2jo1ODx40cMG9SXNes3c/ZiCJ27\ndGPcqKHs/N82jh49StBf5zl7KZT09HR+XDhPLWVITEykVw8fVq7+hfDwcNq09WTU8CEqybtcCX3m\n+djRb/UZHGcdY//FRyzqaY9P40rUsjDBde5xAHS1NBjuapUt7fi2eWvgXvPxbo+hkVG2ZTt27GDX\nzu0EnTrLhSvXQSZjyY8LVRLvNblcztwZ0yhRIvOi1du3btKuXTvq2NdTaZz36dCxM5euhXHpWhg3\nbtxg2rcz+LJ9xxwdjM+t7t4dMDTMvn3j4+Pp27MbS1eu5nJoOK1cWrNj+zaVx35NLpczadKkbBcI\nq9ug/n1o7ebO/fv3WbDoJ1avWqGWOO/bvmvXruX8ub/588wFTv19ia2bNvDX6ZNqia8s0dAJCtpa\n2qxdvwVrmxoANGrclBth16lubcOqVavQ19dHQ0ODZs1bcvtWuFrKEHQ8kC8qW1LX3h6A3n37EXD0\niEp+/aelZzBiw3kevUgC4NTNKCzNjbAuX4zzd17w6t9r2YJvRVO9XDFFOptyxWhqVRq/vx/muQwT\nJk1j6vTvsi2zsbFh1ZpfMTY2RkNDA4dGTQi7HprnWFkt+n4Wnbp2x9Aos3HR09UjMDCQeg0aqTTO\npyQnJzPr2+nMnjtfLfl/PXkqU97avnv27MGuTl0aNMys65jxExg5epxa4gPMmfUdvr6+GKmhIX+f\niIcPuXzpAkOGZ54M0dLRic2//aGWWF9Pnsrkt7bv0aNH6dylG3p6epiYmNDdtzf+u3epJb7S1Hhn\nFHUSDZ0alDYzw6X1m2GsgCOHqFe/IbVq22FnZwdAfFwce3btwL2tp1rKcOtWOJaWVRTPjYyMMDU1\n5c7t23nO+1l8CidvZN52R1NDhncjC45cfcKpm1E41TTH5N8LoVvVKsPJG88U6eb62DHtf1eVvtA5\nK4dGjd9ZVrNmTepm6VkdPXKQ+g0d8hzrtbDQEP48foxBw0YrllWwqETZsmVVFiOn1q1bR6MmTbGs\nUuXTKyuhocO72/fKlSuULFWKHl07Ua+2Df16ded5lot3VSkk5BqBxwIYO3asWvJ/n2tXr1Dpi8p8\nM3US1atXx83FkSuXL6kl1vu2r0wmIyPjzQX5hoZG3L2T98+rIBo6tTtx/Birli9hzvxFimUD+/TE\npkoFKltWxae7r1riJsnl6OnpZVump69PYmKiymL0d7Tk8jwPHKqaMnd3KEeuPuV6RBwX52U28sUM\ntPnt9H0Aejb7gltPX3Lh3guVxf+YhfPnEvXsGUOGjfz0yjkgSRITx41g9oLFaGvn5Y4meZeRkcGi\nRYsYNXZ8vsaNjY3leMBRZs2dz5kLV9HR1WXyBNX36CRJYvSIoSxavDRft3VcXCyhIddo2qwFN2/e\nxKdbD7p36URamvJ3zckNV1dXNm9YT1xsLC+eP+d/v28hJSU5X2LnlBi6/Mz4+fkxf372YZ2xY8eS\nnPzhN05iYiLOzs4qK8N+/z0MH9yf33fuUQxjAqzdsIU7EVEYGhoyuH8vlcXLysDA8J26JsnlGL11\nXCsv1gXdxXbiAX4JvMPu8S3o72iJqbEONb8+AMCtJy/5rrMtpYx1Gehchbm7VTuM+CHfTZ+C/55d\n7PY/hKGhoUry3LLhF6yq2+DQuKlK8suLs2eCMTIyokaNmvka18TEhBZOzlhWqYq2tjZDho0k8NhR\nlcf59Zc1WNvY0KRpM5Xn/THFiplgZm5Ouy+9AOjTbwAxMS+4pabDC28bMGAAjq1a4dKyCb26e+Po\n7IKJSfF8iZ1ToqErBBYvXvxOL0ddggIDmPz1WHbuPUhd+/oA/BkUSGho5pe9np4evfr0JzDgiFri\nV7e25k6WYY+4uDhiYmKoWq1anvOuam5Es+qlFc/3XHiEsZ42za3NOHT5Ccn/3g9x/6XHNKpWiubW\npTE11iVweisuznNnsEtVBrtUZZ6PXZ7L8ra5s2dwJvgv9h8OxLRUKZXle/iAP4cP+GNnZYGdlQWP\nHz3Ew7kpp/8MUlmMnDp0YB9t2rTJ97iVKlUiPstZrJqammhqaH4khXL2+e9ln/9eKluUpUyZMkQ8\nfEiLpg05EXRc5bGysqhUiYSXL8nIyDzGLJPJ0NDQUEsd30dLS4tZcxdw7sp19h0OREtLixo1a+VL\n7JwSDd1nKCIigoEDB+Lp6cmOHTtwdnYmMTGRSZMmMX36dEaOHElCQgJ9+/ale/fu/PzzzyqJK5fL\nGTFkAJt+3051axvF8jPBpxk3bhwpKSkAHDq4j5q1bFUS820tHZ14+OAfTp86BcCyJYvxaNtOJT0c\nU2Ndfuplj7lJ5o+G+pYl0dKUcS8qAaea5mhqZL6pW9Uy5+bjeHadi6DW1wewn3wI+8mHWB1wm9UB\nt5m87Uqey5LVhQsX2LZ1M3/s3KPyMxG3bN/LtdsRXAl/wJXwB5QrX5GDgadp2sJRpXFy4trVq9jY\n2Hx6RRVr3749f536k9CQawBs/PUXWjq3UnmcXXv3809EJPcePOHp06dUqFiRP0//TUtHJ5XHyqpm\nLVvKlC3Hhl9/AcBv53aKFy+htuOgb9u6dSv9enUnIyODJ48f89uWTXj7dM+X2DlVWBu6In3B+P37\n9/Hz8yMhIQEvLy80Nd/8MjMxMWHWrFls3bqVatWqMWXKFA4cOMD+/fvzHPfgvr08j45icL/sw5I7\n9hwgNjqS5g51kSSJ8uUrsGTFmjzHex99fX02bd3G2FHDkcsTsaxSlTXrNqgk77O3n7PscDi/j2yC\nhkzGq7QMhq8/z/m7L5jTtbbiOrrKpY2Y9PtllcTM6llkJB6t33zptXFzRktLi5YtmhMbF4tzizcH\n+itaWLDb/5DKy/Dapl/XsH71cmJi43j5Mp7mDWypa9+Apat/VVvMR48iKFOmjNryfxYZSVu3N0P4\n7dxboaWlxfHAYyz/eR09fTojk8mwqVGTJctV8+PwcyCTydiybTtDBvRl8Q/zKVXajM2//w8tLdV+\nTT6LjKRdlu3rmWX7bvvfDurWtEJLS4tvZ83FskpVlcbOs8J5vTgyKacT+hQyfn5+XLlyhRkzMqen\nadOmDU+ePOHUqVPMmjULZ2dnWrduzcyZM2nQoAEeHh5ER0fTpUsXAgMDP5p3eoak6LUIgiAUpNik\ndIrr58/wquW4A0qnvftj/g+3v1ake3Qf6y6/PptLkiQ0NDJHcF+PzX9KfLLy89GVMNAkRp77Ob30\ndZR/I+tpQbKSJ47lZT66CsPzdz46Yz0NXiq5b/I6H92TuPydj85QR0biq/ydj85EX5O4pPydj85A\nR4ZcyXrm5Rd8XrZvqpLbt7i+JrFKbt/8UtBDkMoq0sfoLl++THp6Oi9evCApKYnixd89g6ly5cqE\nhGTenuvs2bP5XURBEARBzYp0Q2dpacno0aPp3bs3Y8aMee+vkfbt23P58mV69+7NvXv3CqCUgiAI\nhYNMpvyjIBXZocuOHTvSsWPHbMu8vDKvj/n+++8Vy4oVK8bmzZsVz0eNGpU/BRQEQShkCuvQZZFt\n6ARBEATVKqTtnGjoBEEQhJwRPTpBEAShSCuk7Zxo6ARBEISc0Sik1w+Lhk4QBEHIkcLaoyvSlxcI\ngiAIgujRCYIgCDkiTkYRBEEQirRC2s6Jhk4QBEHIGdGj+w/R1crboc28ps9P4Yu98j1to9nHlEp3\ndaYLTed+fOaJDzkyvoVS6V5T5uOfoOydtgFDHW2l0+vk4f2XoeSdkjOUniRFloe0eSFD2YldMpTd\nSHlMmx9EQycIgiAUaYW0nRMNnSAIgpAzokcnCIIgFGmFtJ0T19EJgiAIRZvo0QmCIAg5IoYuBUEQ\nhCKtkLZzYugyv+3fvx9DXQ3+uX9f7bGCjgfSuIE9VlZWtHV3JSIiQq3x/rl/HxNDHera2mBtbU1d\nWxsG9Outsvxdapjxv6EO7BnZmA3961PVzPCddQ6Obar4u5KpAb/0sWfPyMbsHN6IL+uUVUk5Ag4f\noGxxXR7+cx9Jkpg0aRLN6teiWQNb5syYppIYWe3b40erZvVpVr8WX7o5EnY9BICzwadp2agODnbW\ndGrXmqdPHqss5sH9/rRoVA8H+1p4uLTgemhmzHmzv8Ohbk0a2NnQr1c34mJjVRbzbZs3rqdGjRrU\ns6vJl21ac+tWuNpivfbblk00qGuLhYUFA/v2IiUlRS1xDu73p2XjejSyt6WNa0vC/t2+r30zZQJ1\nalRVS+y8kMlkSj8Kkmjo8pFcLmfSpEmULFlS7bESExPp1cOHlat/ITw8nDZtPRk1fIja45YrX55L\n18K4ceMGl66F8cuvG1WSbxkTXaZ5WjP6tyt4LQvmaGgkM9rXULxuZW70TpqZHWpwNPQZXsuCGbzx\nIuPdqlHJ1CBP5ZDL5cyZMY0SJTL34R6/7QQFBXHs9AUCT18g+NSf7Nvjl6cYWUU8fMCEsSPY8NtO\nTp0PwbN9J8YOH0R8fDyD+nTnx2WrOXvlBo6tXNm14w+VxHz8+BHDBvVlzfrNnL0YQucu3Rg3aii/\n//47QYEBBP11nrOXQklPT+fHhfNUEvNtN2/eYNqUiRw9epQLV0Lx6tCRYYMGqCXWa9dDQ5g88St2\n7T3AP//8Q3p6Oj8tWqjyOI8fP2L44H6s/nUzZy5eo5O3D+NGD1O8HnLtCgf27VV5XFWQyZR/FCTR\n0OWjObO+w9fXFyNjY7XHCjoeyBeVLalrbw9A7779CDh6hJcvX6o9tjqkpUtM2hHCk7hkAM7efcEX\npTJ7dDIZTPO0fidNNTMjzt59AUB0wiv+eS7HsvS7vcDcWPT9LDp37Y6hUeY+9N+9kz59+qCrq4uO\njg6du3bHf/fOPMXISltbm1W/bKKiRSUAmrV04s7tcPbs2YOtXV3qNXAAYOTYrxk6cqxqYmpps3b9\nFqxtMn9INGrclBth16lRowaLflqBvr4+GhoaNGvekttq6mXdCLtOlarVKF++PAAtHJ0VPVl1ORF0\nnJaOTlSoWBGZTMawkaPZs1t1P1pee2f7NsncvgAZGRl8NWYEU6bPUHlcVRA9OuGjQkKuEXgsgLFj\nVfNl9Cm3boVjaVlF8dzIyAhTU1Pu3L6t1rgv4+Pp2rkD1tbWeLXz4EZYmEryjU54xZk7mY2WpoYM\nr7rlCLoRBYB3/fLcikx4J83Zuy9wtzVHJoMvTA0oV1yfqxFxSpchLDSEP48fY9Cw0Ypld+/cokqV\nN9u5UmVLboffVDrG28zLlKWlswsAaWlp/LF1M25tPLly5QolTU3p26MzTexrMLhvD54/j1ZJzNJm\nZri0dlc8DzhyiHr1G2JnZ0et2nYAxMfFsWfXDtzbeqok5tsaNmzEvbt3CAkJQZIk9uzyw6mVi1pi\nvSaTyUhPT1c8NzIy4u4d1X9eSpuZ0crVTfE84Mhh6tVvCMCGdWuoUaMW9Rs6qDyuKogenfBBkiQx\nesRQFi1eira2dr7ETJLL0dPTy7ZMT1+fxMREtcU0MjamS9duLPhhMdevX8e5lQtdO7cnLU35W129\nrUejihyf0Bz7SsVZfOQWpkY69GxswU9H3/1CWnAwnA725flzYkt2jWzM2hP3eJ7wSqm4kiQxcdwI\nZi9YnG0fvr2d9fT0kctVv43XrlqGbdUKnA0+xfQZc4mNjeVEYADfzPyeE2evoKOryzeTxqs87onj\nx1i1fAlz5i9SLBvYpyc2VSpQ2bIqPt19VR4ToGy5cnw7YzZ16tTBomwp1q5eyYxZ6hkmfc3RyZnj\nxwK4HhpCWloaa35eSXJyslpjnjgeyM/LlzD7+x94+vQpP69cxjcz56o1Zl6IHl0RcO7cOZ4/f67y\nfH/9ZQ3WNjY0adpM5Xl/iIGB4Tsf0iS5HCOjd49lqYqpqSk/LllOpS++QENDg1FjxvHsWaRKTyLY\neuYhLb7/ky3BD9g8sAHT2lnzc9A9Xr7nvo+Lu9VmReAdmn9/AvcfT9G7qQW1K5ooFXfzhl+oVt0G\nh8ZNsy1/ezsnJckxNFT9Nh44dCTX7z1h0LCRtHNtiYmJCc1bOlG5SlW0tbUZOGQkQYEBKo25338P\nwwf35/edexTDbABrN2zhTkQUhoaGDO7fS6UxX7ty+RI/zJ/H3bt3efj0OTNmzaVr5/ZK338yJ6xt\narDwxyX08e2Og4MD1jY1MCleXG3x9vvvYcSQ/vy2YzfWNjUYO3YsX0+aSvESJdQW879KNHRZ7Ny5\nUy0N3T7/vezz30tli7KUKVOGiIcPadG0ISeCjqs81mvVra25k2XYJS4ujpiYGKpWq6a2mDExMdy/\ndy/bsvT0dLS18t6LrVzKAAfLNyfxHLwWiaGuJo2qlOQrt2oEft0cgDImegR+3ZyShjrUKFeMA1ef\nAhAZn8Llh3HYWyj3xXX4gD+HD/hT28qC2lYWPH70EHfnpkRGPuV2luHge3duY2Vtk4eaZhd+M4w/\nj2fe5Fomk9Ghsw8JL+MxMTEhPv7NMKympgaampoqixsUGMDkr8eyc+9B6trXByAwMJCw66EA6Onp\n0atPfwIDjqgsZrb4xwNxaNQYCwsLADp5d+VG2HWio1UzPPshPXx78/fFq1y4cIEaNWtRs6atWuIE\nHT/GlAnj2LHngGL77tu3j28mT8DGsgIuLRrzKOIhNpYV1HbmpzLE0OVnLDU1lfHjx+Pj40Pv3r15\n9OgRgwcPxtfXF29vb65evcrp06cJCAhg8uTJPH6sutO0AXbt3c8/EZHce/CEp0+fUqFiRf48/Tct\nHZ1UGierlo5OPHzwD6dPnQJg2ZLFeLRth6Fh3k7G+JgL58/Rxq0VUVGZx87Wr1tLxYoWVLa0zHPe\nJQ11mNOxJqWNdQCoY2GCloYGLj+cxHlh5gPgaVwyzgtPEiN/xYuEV7SsXgoAYz0t6lQ04fazd4/l\n5cTW7XsJuR3B1fAHXA1/QLnyFTkUeJr5Py5jzZo1yBMTSUxIYMvGdbTv1CXP9X3teXQ0I4f0U1w6\n8PeZv0hNS6VPnz4Enz5JWOg1ADZvWEcLR2eVxJTL5YwYMoBNv2+nepZG+9SpU0yb9JXii/fQwX3U\nrKWehqCalRVnzwQrfngePnQA8zJlKFWqlFriAdy5c5smDe2JjY0lNTWVRQvm0cNX9T1WuVzOyCED\n2Pjb/7Jt35cvXxJ2N4KwuxEE/BlM+QoVCbsbga6ursrLoKzCOnT5n7hgfPfu3ZQqVYpFixaxf/9+\nAgIC8Pb2xsXFheDgYNauXcuyZcuwsbFh+vTplCtX7qP56WmBhobyO04G6OvIMNBR387XM9Zn27Zt\njB49nMTERKpWrcqGDRvQy/Uez3kZv2zrxs3rw3B1aoaGhgbly5fHz28nxvq5C3p15odPOjj2dfbp\ndIKnZv+xUL6Efrb0i7vZZXt9pW/dXJXlQzQ1oHQxHQb08uFO2BXcWjZEJpPRvXt3evl0VEkMgPYe\nzjyaNpVuHTzIyMhAV1eXP7Ztw8LCgg3r1zPAtwsymYxatWqxZs0aShfLe+/50J59PI+OYuhbw5KH\nDx/myZMntGxUF0mSqFixIht+XUcJA9X1JF/r0tGL61cv0bhxY2QyGcWKFWPH9u0Y66k+1mt2Nazo\n0N6Lpg3rIpPJ6NatG4MH9M19Rrof7z8c3ruf59FRDBuQ/RrTEydOYG5uDkC8gRYaMihp+OnPzotE\n1R0D/5SC7pkpSyapc9D7M/Hdd9/RuHFj3Nwyz3R6+fIlM2fOJCIiglevXmFgYMDmzZvx9fVl+vTp\nWFlZfTQ/+SvlN5mBjkyp9HlpWPW0QNmpz5SdH0vZekLe5qOr/Y1yx6nyMh9dGRMdnsbl/iSXvPzK\nNS+mTWR8qlJplZ2ProSBJjHy9E+v+B7amsrV1UhXg4SUDKXS5kVe4r5KUy5dSUMtpRutnDSIqtB8\n0Sml054cn3/nKLztPzF0qampSUbGmzffxo0bMTc35/fff+e7774ruIIJgiAUIoV16PI/0dDZ2tpy\n5swZAI4fP86qVasUB7kDAgJITc38Zfz2dTSCIAjCG+JklM9YmzZtSEpKomfPnmzcuJH169ezfv16\n+vXrR+3atYmKimLnzp00bNiQUaNGcevWrYIusiAIwmensPbo/hMno+jo6LBgwYJsyw4ePKj4u1Wr\nVoq/R4wYkW/lEgRBENTvP9HQCYIgCHlX0EOQyhINnSAIgpAjBT0EqSzR0AmCIAg5UkjbOdHQCYIg\nCDmjUUhbOtHQCYIgCDmirnYuKSmJSZMm8fz5c1JSUhg2bBjW1tZMmDCB9PR0SpcuzcKFC9HR0WHv\n3r1s3LgRDQ0NunTpgre39yfzFw2dIAiCkCPqOkZ3/PhxatWqxcCBA3n06BH9+vXD3t6e7t274+Hh\nwY8//siOHTto3749K1asYMeOHWhra9O5c2dcXV0p/olZJv4T19EJgiAIeachU/7xMW3atGHgwIEA\nPHnyBHNzc86ePau49MvJyYng4GCuXLmCra0txsbG6OnpYW9vz8WLFz9ZbtGjEwRBED4LPj4+mRPQ\n/vwzffv2RUcnc7YSU1NToqKiiI6OpmTJN9N1lSxZUjFbyseIhk4JebnBsirS56e8lFXZtGent/r0\nSipOW7LxWKVjJp3/icqtJuQ6XcyZn5SOCWBioNxMBWnpyt8kWdmbM2vm4X2kbNq8DrNpaSo34KVs\nOgAD3c/7K1ndlxds27aNsLAwvv7662yT7H5o7oGczkkghi4FQRCEHFHXvS5DQkJ48uQJADY2NqSn\np2NoaEhycjIAkZGRmJmZYWZmlm3y3WfPnmFmZvbJcouGThAEQcgRWR7+fcz58+f59ddfAYiOjkYu\nl9OkSRMOHz4MwJEjR2jevDl2dnZcu3aN+Ph4EhMTuXjxIvXr1/9kuT/vfrIgCILw2VDXURcfHx+m\nTp1K9+7dSU5O5ptvvqFWrVpMnDiRP/74g3LlytG+fXu0tbUZP348/fv3RyaTMXz4cIyNjT+Zv2jo\nBEEQhBxR1zE6PT09Fi1a9M7y9evXv7PM3d0dd3f3XOUvGjpBEAQhRwrpjVFEQycIgiDkTGG9BdgH\nT0bZsWPHRx9C7gQdD6RxA3usrKxo6+5KRESE2mOmpqYy8evxyGSyfImXNe748ePR186fuLv9duJQ\nvy7W1ta0cmxOaEiIymO4N61B0vmfsChbEkN9HVZ/040rO6dwffe0bOtVNC/OvhVDubpzCn9tGU+L\nelVVWo6C2KebN66nfvIO3R0AACAASURBVJ1a2NjY8GWb1ty6Fa72mPmxT9+nID6nBRHzv+aDDd2F\nCxc++hByLjExkV49fFi5+hfCw8Np09aTUcOHqD2ud0cvjIyM1B6nIOM+fPCAUSOGsn3nbm7cuEHH\nTp0ZMqi/SmPo62oza2Q7nscmAjB5gBuG+jrU6TwP10HLAKhULvMi1uVTu3Lo1HVqd5rLkJnb2Din\nF3q6yl3v9j75vU9v3rzBtCkT2bv/MGFhYXh16MiwQQPUGjM/9un7FMTntKC+G5SlrssL1F5uKQdX\n3GVkZPD8+XNKly6dH2X67CWn5W79/fv8mT9vDn+ePoOeFkTHJlDOrCSPIp/n6IwhZZ0JDqZR48bo\na8u4de8hFSpUUFust+M6Nm+MTKZc3JxeBAqZtwu6HhpCKxdX9LVlnL90jVaOzXgaHZurmB+7YHzO\nKE+exyYyqHMzWg9ezraFfZmx6gCHT4cBmReMf71oF5v2nuVhwGzKOk1BnvwKgJMbxzJr9SGO/BX2\nTr7KXDCuin2amwvG9+z2Y8niRQSeOI2RrgaXQm7g1KwREZEvchUzNxd9q2qf5vbEiYL4nKoqpl4+\nHYTqvP7Tt9v6kB197VVYktz55HV0wcHBuLi44OvrC8DcuXMJCgpSd7mKlFu3wrG0rKJ4bmRkhKmp\nKXdu31Zr3EaNG6s1/88hbtmyZWnl4gpAWloaWzZvoJ2nl8ryr1mlLM4O1Vm6NUixTJJAUyP7R6dK\nxVJUqViK6JgERSMHcDfiOdW/+PQFrTmV3/u0YcNG3Lt7h+uhIUiSxJ5dfji1clFrTHXv0w8piM9p\nQX03KKuw9ug+2dAtXryY//3vf4re3JAhQ1i5cqXaC1aUJMnl6OnpZVump69PYmJiAZWo6FmxbAnm\n5uacPnWKWXO/V1m+y6Z4M37Bzmy9oMCzNxns3QxdHS0qmmfeNV1XRwsDPR2SX2Xv7ielpGKgr6Oy\n8uS3suXK8e2M2TRpaE/JkiVZu3olM2bNy5fY6tqnH1IQn9PC9t2gIZMp/SjQcn9qBQMDA0qVKqV4\nXrJkSbS1VXfMQR0SExNxdnYu6GIoGBi8uZXNa0lyeYEcPyuqho8cTXR0NCNGjsa5ZVOSkpLynGf/\njk0IuxvJX1fuZVs+75cjPI6K49zvE1g6pQsAcS+TSEx6hZ5O9jEkAz1tEuWvKKyuXL7ED/PncS3s\nNjExMcyYNZeundvnanhZWerYpx9TEJ/TwvbdIMvDoyB9sqHT09Pj77//BiAuLo7ffvsNXV1dtRes\nKKlubc2dO2+GIuLi4oiJiaFqtWoFWKqi4UZYGIHHAoDMYzJdfLrxMj6e8Js385x3u5a1aNeyFvcO\nzeTeoZlUMC/OqU3jqF/TgqGztvF/9u47LIrj8eP4++hdsaCiiIhSFHtBLBHEXqLGYMEYa9REUX+x\no8aaYvSb2DUae4m9l4A1sSAaQQQFQWygoqAoVTngfn8QLhqj4N3tneC8fO55vON2P7NXdm53Zmdq\n9/iO7qNXAhBx4wGx8YmULmmB+UtHcI52ZYm8maB2WXTl1MkTuDfxwK5yZQB6+PQiKvLaK+MNapqU\n7+nb6OJ7WtT2DTKZTOWbLhVY0U2fPp3Vq1cTHh5OmzZtOH36NLNmzdJG2d5JWloaAwcOxNfXlxUr\nVgB546f5+vry+eefM3HiRLKy8n5Z//zzz/Tt25fevXtz8OBBACZNmsS0adPw8/PTeNlaenoRd/cO\nZ8+cAWDxwp/p0Kkz5ubmGs/60CQlJTJkUH/u378PQNC5s8jlchyqVlV73d1Hr8S+7TQc2n+DQ/tv\niH/4lOaf/0QjN3t+GJPXZuTiUA6Ag39EkJr+guPB1/mq90cAfNSgGuVLW3I65P1sbymM6k5OBJ8P\n4vHjxwAE/H6YcuXLv3KWR9OkfE/fRhff06K2b5BqPjqpFarXZVGwefNm7ty5g7+/P4cPH2b+/PlY\nWVmxbt06SpYsyY8//oiLiwu2trZs3bqV+fPnk5WVRffu3dm1axczZsygTJkyjBs3rsCsXMW7v3Gn\nTp1i9OjRpKenU61aNdatW0f58uVV3NqCPXz4kJYtWwJw/fp1HB0dMTAw4Pjx41SsWLFY5S5dupSl\nS5eSm5uLsbEx33//PR07dpQkS5d09Z7OmDGDLVu2IJPJsLKy4ueff6Z58+aS5YHu3lNtf081kfk8\nW3u9LvtuvKzyspv71dVgSd5NgRXdxYsX+eGHH4iNjUUmk+Hk5MSECRNo0KCBtspYKLNmzaJRo0Z0\n6NCBpKQkWrVqhb6+Pm5ubgBkZGTQvn17FAoFO3bsUH6QkpKSWLlyJUuXLqVVq1a0bdu2wKx3vbzg\nZSYG6i3/IWSq+tvL1FBGply1ZdWdj8604Zh3Xk6d+ejUeX1VnY/OwliPtBeqLavqnHLqvKfqnC4r\nat8ZbVV0n20KU3nZTZ/V0WBJ3k2BL8+sWbPw9/enfv36KBQKLl26xMyZM9m/f782yldoCoUCvb+7\nfOfm5mJoaEiZMmXYuHHjK89bt24dn376KcOGDXttHe97JxtBEARd0vVlAqoqsI2udOnSeHh4YGxs\njImJCc2aNcPW1lYbZXsnDg4ORPw9TFBwcDAlSpQA4Mbf16Ns3LiRqKgoateuzcmTJ8nNzeXFixfM\nnj1bZ2UWBEEoSopqZ5Q3HtHFxcUBUKtWLdasWUPTpk3R09MjKCiIGjVqaK2AhdWtWzdGjBhB//79\nladVv/32WyZPnoyhoSE2Njb06tULIyMj3N3d6dWrFwqFAl9fXx2XXBAEoWjQdacSVb2xja5Vq1bI\nZLL/bC+RyWQcP35c8sK9r0QbnbSZoo2uYKKNrmCijU7zBm4NV3nZtb1rabAk7+aNL8+JEyfeuFBI\niOrjnQmCIAhFUxE9oCu4M0paWhr79u0jOTkZyJsmZNeuXZz5+7oPQRAE4cOg66G8VFVgZ5QxY8Zw\n/fp1du/eTXp6OidPnmTGjBlaKJogCIIgqK/Aiu7FixfMmjWLihUrMnHiRDZs2MCRI0e0UTZBEATh\nPVJUZy8o8NSlXC4nIyOD3NxckpOTsba2VvbIFARBED4cur5MQFUFVnRdu3Zl+/bt+Pj40LFjR0qV\nKkXlvwd4FQRBED4cRbSeK7ii69Onj/L/Hh4ePH78+L28jk4QBEGQVlHtjPLGim7hwoVvXOjo0aOM\nHj1akgIJgiAI76ciWs+9uaLT19fXZjmKlNxcdSZ8kKm0vJ6OhiRQfVtV206AtBeqXTVramhIqopX\n3Mb/MV+l5dRZvvqYfSrnxS3pqvLykf/ronKuqnLU+BypuqyBvm6+M8/lOSotZ2Kgr9ay2lDs2uhG\njhypzXIIgiAI77kCu+m/p4pquQVBEAShULQ0QpogCIJQ1BXVU5eFOqJLTk4mPDxvMM/cXNUGdRUE\nQRCKNj2Z6jedlrugJxw8eJBevXoxefJkAGbPns2OHTskL5ggCILwfim2Fd3atWvZt28f1tbWAEyc\nOJHt27dLXjBBEATh/VJUJ14tsKKztLTE1NRUed/ExARDQ0NJC1WcHTp0CHNjPe7cvi15llwuZ+L4\nschkMuLj4yXPu3P7NiXMjahXyxUXFxfq1XJlyKD+kmQd3LebVs0a0qyBG13aehJ5LeKVv8+YMpGG\nbtU1mnnk0AE8PRrgUb8Wndq0JPJqXuaZM2do3qguDWs5061jGx48uK9WToe6Ffh9kicnp7Zi1/81\nx7mCJXoymN7DjVPTvDkxtRUAZkZ5XcrLlzBhzTB3TkxtxcmprejXvIpa+f+2cf1aGtZ1w9XVlY87\ntiUmJlqj639bbo0aNWhQp6bWcrX1nZHL5UydNA5rMwPu/Z2TnZ3N1EnjaFy3JrWcq7LoZ/UueZFC\nsT2is7a2Zs+ePbx48YKrV68yb948SpUqpY2yFTsZGRlMmjRJa6+fzyddsbCw0EpWPtuKFQkNjyQq\nKorQ8Eh+XbNe4xnxcXeZMGYk63/bxdlLEXTp1oMxXw1V/v1qeBhHDu7XaOaD+/cYOWwQv6zZSFBI\nOD18ejN29FekpqTQs2dPFixdwV/h12nVui27d2xTOcfW2pTve9Vh8C/BeM05waHQ+8zvW49eHvbU\nsitB2+9P4v1t3lyRI9rmVeTf96lDeNxTWs05Qe/F55jwsStVbTTzvl+/HsVU/4nsPxRAZGQkXbt/\nwldDh2hk3YXJPXr0KJfCrmotV1vfGV+f7pibv5qzatUq/rp4gT/PX+LMhVA2b1jHubOnJS/Luyiq\ngzoXWNHNnDmT8PBw0tPTmTp1Ki9evGDOnDnaKFux8+3sGfTr1w8LS0ut5E3yn8a06TO1kqVNhoaG\nLF+9AbvK9gC08PQi9kber/3c3Fwm/J8fk6bN0GimgYEhK9duwtk1b/g796bNiIq8xpFD+6lfvz4N\nGzcBYNTX4xkxSvXZyrNzcvFbf4l7yZkAnL2eSNVyFrjYWnHx5hOysnPJn4DduYIVAJvP3GbNyZsA\nPHz2nLjHGVQvr5mddVTkNRyrVce2YkUAPvJs9drRsxTycytqOVdb35nxk6cw+V+f0aNHj/Jpzz6Y\nmJhQokQJfPv158DePZKX5V3oyWQq33SpwMsLrKys+Oabb7RRlmItIiKcE8eP8dfFCyxdtkwrmU08\nPLSS87LUlBR6fdqdmOgo7CpXYe68n3BxddVoRrnyFShXvgKQd7pn2+aNtO+YN9rHhjWrcK3pRoNG\n7hrNLGtjg3ebdsr7xwMDaNCwMRHhVyhTpgyf9/6UqKhr1K5Tj7n/W0jpMmVUynmU8oJHKYkA6OvJ\n8GlSmcArCZy9nsjXnVxYcfSGcvSM09fznncs4qFyeVtrU6raWBAe90zVTX1F48ZNuHUzlmtXI2hU\nrxb79uzGy7u1RtZdmNyIiAjsq7lqLVdb35nG7q/nyGQycnP/GRnF3NyCm7E3tFKe4q7Aiq5ly5b/\n2ZB46tQpKcpTLCkUCkaP/JL//byoWLdvWlha0rNXH0b/3zicq9kzd95P9Pq0G5fCrmJgoPlLNlcu\nW8xPc7+lSlVH1v+2k4SEBFYuW8Th42dISdHMjv6//HnyBCuWLGTPoUCWLVnAicBA9v1+ArvK9owZ\nMZQpE79mxeoNamUM8qzKmA7O3E5MZ8jKYB6lvKB93Qpc+q4d2X8PibXl7O1XlrEyNWDlkEYsCYjm\n/t9HhOqqYGvL9JlzaNq4PpaWlpiZm3Mk8KRG1l2Y3Lp162o1V5fatGnD0mUr6NXnM3Jyctj+2ybM\nzM11XaxXFNURRgrc+2zZskX5f7lcTlBQEC9evJC0UJqWnp5Oly5dOHHihE7y1/y6EhdXV5o2a66T\nfG0pXbo0Py1cAuSNzTlqzNf88N1sYmKicXXV/IwXQ7/y44svR7Jn5zY6tWlJg3p1+XriFEpaW0tW\n0R0+sI9J48aweedenF1rYGVVAm9vb6o6VlOWqVe3zmrnrDl1kzWnbtK1QUX2fN2C1aduUtrCGLcJ\nR5Dn5HJ70cfM6FGLKduvAFDW0pgNXzXhaHgCSwJj1M7PF3Y5lPlzvyc88gau1avw69oN9Pq0GxdC\nrkjaky4/9+bNm5QqV4mtWzZpJVeXhgwZwtXrMbRu2ZRy5cvj2ao116MidV2sVxTVl77ACrpixYrK\nW5UqVejTpw+nT79fDaTvu4MH9nPwwH4cKlegfPnyxMfF8VGzxvxxqnj9Qk1OTub2rVuvPJaTk4Oh\ngWaPYqOvR/LHyeNA3umeT3x6k5aSwrFjx5gxZSJu1exo79mUe/FxuFWz09gPsz9OHsd/wtfs3HeY\nevUbAmBnV5lnz/6pVPX19dFTY0D0auUsaO5cVnl/36V7WJoa0sKlLL+HPeC5PEc5yLF79dIAWJgY\nsGmEB7suxPHT4esqZ/+XUydP4N7EA7u/56Ds4dOLqMhrJCUlaTTnTbmVtZyrSwYGBsz+7kcuhl3j\nYMAJDAwMqFHTTdfFekVRbaMrsKILCgp65bZnzx7u3r2rjbKpJS0tjYEDB+Lr68uKFSsACA4Opnfv\n3nz22WeMHTuWrKwsUlNTGThwIH369GHFihW0atVK42XZs/8Qd+IfcuvuAxISEqhkZ8efZy/Q0tNL\n41m6dOmvi3Rs501iYl7b0drVq7Czq4xD1aoazXmclITfsEEk/N2N/8L5c8iz5dy7d4+IG3FE3Ijj\n91PnqFjJjogbcRgbG6udmZGRgd/wIazbsh0nl3/aHDt26coff/zBtYi8kYM2rPmVll6qf4ZKWxiz\n4PP6lCthAkDDqqUw0JNx+1E6XjVs0H+pn3b0/VQAxnd25Vx0Er/+3SFFk6o7ORF8PojHjx8DEPD7\nYcqVL08ZFdsg3/dcXdq8eTODPvclNzeXB/fvs2XTBnx6++q6WK8oqr0uCzx1ueyljhMymQwLCwtm\nznz/e/Lt27eP6tWr4+/vz+HDhzl06BDTp09n7dq1VKhQgVmzZnHgwAEyMjJwdHRk6tSpbN68WdfF\n1piHDx/S1rul8n671p4YGBhwOOC4siebprVu05Yvhn1Ja8/m6OvrUb5CRTZv3anxKZ88mrVgzLhJ\n+HzcntzcXIyMjfllzSasrKx4nirXaFa+Iwf38zgpkeH/ui5w/+/HWbt2Lf19fUAmw9W1Jj8tXq5y\nTnDsYxYHRLNlZFP0ZJCVncuItX9x6dYT5vSszalprciftWbW7rxeiH2b2fPw2XM8a9go17P61E02\nnbmtcjnydezUhcshIXi3bIa+ngwLSys2bN4m+enD/FwPDw8UyLCykj5XW9+ZRw8f0rndPz+GurT3\nxsDAgJMnjrN1+07q1XTCwMCA6bO/U54Sf1/o+no4VckUCsVbJ3u6evUqNWvW1FZ5NGbWrFk0atSI\nDh06kJSURNu2bSlXrhxHjhwBICAggIsXL5KdnU3jxo3p2LEjCQkJ+Pr6FtiWl5ur0Nn8cIIgCC97\nmplDSVPtzEc366jqvUC/aaO7SrvAI7q5c+eyYYN6Pch0QaFQoKeXd2Y2NzcXmUzGy3W6XC5XPpb/\nvML+Wsyb21O1ySDNjGRkZGl34lUTg/wyvztVJ09VdTtB9YlXbSwNeaTiEZ2+Gq9vaXMDHqe/e5nr\nTjykcmbckq7YjdTuxKsWxnqkvdDuoO7qZBroq95HUJ3vjKqTp5Y01edppmrLaouuT0GqqsCKztbW\nln79+lGnTp1XusaPHj1a0oKpy8HBgYiICNq1a0dwcDAlSpRAJpNx//59bG1tuXDhAg0aNCApKYmI\niAjat2/Pn3/+qetiC4IgCBpWYEVXqVIlKlWqpI2yaFS3bt0YMWIE/fv3p0GDBkDezAtjx47FwMAA\nOzs7OnXqREpKCl999RX9+vWjadOmyqM7QRAE4VVFtcXmjRXd/v37+fjjjxk5cqQ2y6MxVlZWbNy4\nUXl/1KhRAPz222+vPC8zM5MRI0bQokULQkNDuXjxolbLKQiCUFTIKJo13Rsrup07d/Lxxx9rsyw6\nYWlpybp161i6dCkAU6ZM0XGJBEEQ3k/F7ojuQ2FlZcXq1at1XQxBEIT3XrGr6EJDQ/H09HztcYVC\ngUwmE2NdCoIgfGCK6vBrb6zoatSowU8//aTNsgiCIAjvsWJ3RGdkZCTZCBqCIAhC0VNED+jeXNHV\nrl1bm+UQBEEQPnA//vgjly5dIjs7m2HDhlGrVi0mTJhATk4OZcuWZd68eRgZGbF//37Wr1+Pnp4e\nPXv2xMfH563rfWNFN378eI1vhCAIglB0STkLwfnz54mJiWHbtm0kJyfTvXt3PDw88PX1pUOHDvz0\n00/s3LmTbt26sXTpUnbu3ImhoSGffvopbdq0oWTJkm8ut2SlFgRBEIoVPZnqt4I0atSIhQsXAnm9\n4TMzMwkODsbb2xsALy8vgoKCCAsLo1atWlhaWmJiYkL9+vUJCQl5e7nV3nJBEAThgyDlND36+vqY\nmZkBeddxf/TRR2RmZmJkZATkTeycmJhIUlISpUqVUi5XqlQp5dRgb/LBX0enCnWP3otSg65qwzKr\nt6yZkeojsauzrDqMDd79N2P0z+oNyKDq8qU6/KjScpnHJlK20zyVlk3+faJKy4F6gzPrgiqfBU0s\nqw16WhgZ5dixY+zcuZM1a9bQtm1b5eNvmmingAl4AHFEJwiCIBSS1BOvnj59mhUrVrBq1SosLS0x\nMzPj+fPnQN58gTY2NtjY2Lwy0/yjR4+wsbF50yoBUdEJgiAIhSRlG11qaio//vgjv/zyi7JjSdOm\nTQkICAAgMDCQFi1aUKdOHcLDw0lJSSE9PZ2QkBAaNmz41nWLU5eCIAhCoUjZ6/Lw4cMkJyczZswY\n5WM//PADU6dOZdu2bdja2tKtWzcMDQ0ZO3YsgwcPRiaTMWLECCwtLd+6blHRCYIgCDrXq1cvevXq\n9drja9eufe2x9u3b0759+0KvW1R0giAIQqEUpY50LxNtdFqyd/cu3BvWw8XFBW/PFlyNiJA8Uy6X\nM3H8WGQyGfHx8ZLnATy4f58uHdpSpUoV3BvU4cxp7czavnH9WmrUqEGDOjX5uGNbYmKitZLZsK4b\nrq6uWsuU+nPU3r0qmccmUrmcFVM+b0bcLj8urxnC5TVDAPi4WXUAqlW05si83lxeM4SLqwbRt42b\nRstx6uQJPBrVx8nJiU7t22jt86uL74wu9g2q0pPJVL7ptNw6Tf9AxN29y6iRX7Jj116ioqL4pMen\nDB86WPJcn0+6YmFhIXnOy4YOHkDbdu25ffs2P/5vAb8sXyp55vXrUUz1n8jRo0e5FHaVrt0/4auh\nQ7SSuf9QAJGRkVrJlPpzZGpswOwhnjxOyVQ+tmJfCHUH/UrdQb8CsP9sDAArx3dkz+nr1B30K10m\nbuOH4V5Uq2itkXKkp6fzed/eLPvlV6Kjo+nYqQujRgzXyLoLou3vjK72DaqSutelVERFpwUGhoas\n3bCZyvb2AHh6eRMTfV3y3En+05g2fabkOfni4+K4HHqJ4SP8AGjp6cXGLdskz42KvIZjterKQcg/\n8mxF5DVpfxXnZ9pqMVPqz9HUz5vz29EI0jKyCnxuTYeynAy5A0DCk3RuxCfjal9GI+U4dfIEVRyq\nUq9+fQD6DxzEsaOBpKamamT9b6Pt74yu9g2q0lPjpku6zv8gVKhQAe/WbQDIzs5m08Z1dO7SVfLc\nJh4ekme8LPxKGPZVHPhmyiScnZ1p19qTsMuhkuc2btyEWzdjiYiIQKFQsG/Pbry8W2sl89pV7WVK\n+Tmq6VCGVg2qsGjXX6883qp+FU4u/IywtXlHq0aGeRfknwq9g4+XKzIZVK9UCvtyVlyIvK+RssTE\nRFO1qqPyvoWFBaVLlyb2xg2NrP9ttP2d0dW+QVUymUzlmy6JzihatHTxQr7/djZVHauxbeceXRdH\n4549e8rViHAm+U9j0YKfWLJ8Jb49exB2LRoDA+k+ahVsbZk+cw5169bNu8jU3JwjgScly3s5s2nj\n+lrLzCfF52jx6HaMXXKU7Jxc5WOXYx6SlpHF8n0hmJsYcn/PaMb2cuf7TecYv+w4xxb0ZUT3BpQw\nN+brpcd4mJyukbJkZmRgYmLyymMmpqakp2tm/e+jorJvKKJ9UYrnEZ1cLsfHx4eJE1UfdkgKI/xG\nk5SUxEi/0bRq2YzMzMyCFypCrKxKYFOuHJ0/zvtFOmDQEJKTn0jeSSPscijz537PzZs3iUt4zMzZ\n39Hr026FGhpI3czwyBskJydrJTOfpj9HgzvVIfLuY85F3Hvl8UNBN1i48yJZ8hySU/NGp+jYJO9I\n67cZ3Zm17jQVP1mEc98VjPFpjLurrVrlyGdmZq4cDSNfZkaG1tubtamo7BtEZ5T3SGJiIllZWcyd\nO1fXRQEgKjKSE8ePAXmH/j179yE1JYXo6+/vuXhVVLa3Jy01ldzcvKMCmUyGnp4e+nrSjj956uQJ\n3Jt4ULlyZQB6+PQiKvLaK8MESZVpp8VMqT5HnZtWp7NHNW5tH8Gt7SOoVNaSM0v7M7BjHSzNjF55\nrjw7l9JWptR3Ks/W49cAuJeUyvmr92haq5Ja5cjn7OJCbOw/pymfPXtGcnIy1apX18j63ycfyr5B\n14plRff9999z9+5dJk+ezIQJE/D19SUnJ4cff/yR3r174+Pjw969ewE4d+4cnTt3ZsCAAcycOZPF\nixdrvDxJSYkMGdSf+/fz2jCCzp1FLpfjULWqxrN0qaZbLcpXsGXdmrweert37aBkSWuqOjoWsKR6\nqjs5EXw+iMePHwMQ8PthypUvT5kymukc8b5kSvU56j5lJ/Y+S3DouRSHnkuJT0yl+Yj1tKxbmVmD\nPgLA+O+2uSPBsTxJzeRRcjqdPKoBUNLCmCY1K3L1lmYq+ZaeXsTdvcPZM2cAWLzwZzp06oy5ublG\n1v8+KWr7BpkaN10qlm10EydO5N69e9ja2nLz5k22bNnCxYsXiYmJYevWrWRkZPDxxx/TunVr5s+f\nz48//oizszN9+/alWbNmGi9P8xYfMWGSP53bt0GhyMXIyJj1m37DyspK41n5Hj58SFvvlsr77Vp7\nYmBgwOGA48reiZomk8nYtHUHw4cM5Of5cylT1oaNv22XtH0OoGOnLlwOCcHDwwMFMqysrNiweZuk\nDeD5md4tm6GvJ8PCUvpMbX+Oxi87ztL/a0f4ui/Iyc07Jbtw50UUCvCdtZcfhnkxa/BHyGQyNgaE\nE3jxpkZyTU1N2bB5K/83agQZGelUdazGytXrNLLut9HFd0YX+wZ16PoyAVXJFNpoVNCy+Ph4Ro0a\nhZeXFxYWFgwcOJC1a9cil8sZOnQoAMOHD8fPz49BgwYRHBwMwLJly8jJycHPz++t689VKHR+zlkQ\nBAEgU67A1FA7+6PfQu8V/KQ36FNPmh8LhVEsj+heZmhoCPDaL225XI6e3qtnbgv7a/xFNqg625qp\noYxM+bsvq86RgokBPM9Wbdn8X/LvytxIRnqWasuq+tvLwliPtBe5BT9Rw1TN1S/MkO5voOrnCNSb\nj860tWrt3qrO6I542wAAIABJREFUR6fOZ1cd6uSq+vlV5z3VlqLa1lVUy/3O3NzclEdu6enp3L17\nF3t7e8qWLUtsbCw5OTmcPXtWx6UUBEF4f4nr6N5zDRs2xM3Njb59+5Kdnc3YsWMxMzNjzJgx+Pn5\nUalSJapWrfraUZ4gCIKQp6g22BTLiq5SpUrs3r37tcf/7//+77XHTExMWLlyJZUqVeKbb75RdlEX\nBEEQXqXrIzNVFcuK7l0oFApGjhyJubk5pUuXpl27droukiAIgqBBH3xF16JFC1q0aKHrYgiCILz3\nimrDzgdf0QmCIAiFI05dCoIgCMVa0azmREUnCIIgFFIRPaATFZ0gCIJQOHpF9JhOVHSCIAhCoYgj\nOkEQBKFYkxXRI7qi2ltUEARBEApFHNGpQNWBjvPIVFreQF83v6TUGXhY1WVz1BiXWdXuz+q9p6DK\n4tJOR/tmT45M0Pqy1p+uVGm5zL1DVV72yY4vVFouj0zlwZlfZKv2ATY11FdrWW0Qpy4FQRCEYk10\nRhEEQRCKNXFEJwiCIBRroqITBEEQirWi2utSVHSCIAhCoajRN02nREUnCIIgFEpRPaIT19FpyZZN\nG2hUrxaVK1fmi4Gf8+LFC8kz5XI5E8ePRSaTER8fL3ney7ljx47F1FB7uQ/u36dNmzbUcHLAvUEd\nzpz+U5IcuVzOlInjKGGqz72/t23dunXYlbOmYZ0aytvK5Uslyd+7exfuDevh4uKCt2cLrkZESJKj\n7cz2DezI3DuUyjYWGOjLWDCsGZeX9ARg0fDmGOjL0NOTcXlJz1duCZsH8GWnmhorx8ED+3FvWA9X\nV1dJX1+5XM7USeOwNjNQfo5ycnKYPP5rGtWpgXs9N0YMHUxaWpok+R8aUdFpwbWrEUyeOI49+w9z\n584dcnJyWPC/eZLn+nzSFQsLC8lz3ofcoYMH0KFDB65F3+LH/y3gF4kqmj4+3TD/j23r/HE3/gq7\nprwN/XKExrPj7t5l1Mgv2bFrL1FRUXzS41OGDx2s8RxtZ5oa6TP7c3cepzwHYEy3OtiUMKX+qB0A\n1K5SmkFtXcnNVVB35Hblrfm4PSSlZLLn3E2NlOPevXsMHTyAdRs2ExkZSc/effAbMVwj6/43X5/u\nmJu/+jlas2YNYZdDOHMhlKBLV3iR9YIF8+dKkq8qmUz1my6Jik4L/jh1kpaeXlSys0Mmk/GV32j2\n7d0tee4k/2lMmz5T8pz/yp05U3u58XFxXA69hJ+fHwAtPb3YuGWbJFkTJk3Ff9oMSdZdEANDQ9Zu\n2Exle3sAPL28iYm+XuQzp/ZpyG+nYkh7LgfgTMQDpm64QO7fV+EHRSXgZFviteUm9azHppPRJCRn\naqQchoaGrNu4BdcaNQBo2rQ5kdeuamTd/zZ+8hQm/+tzFB4ejrtHU4yNjdHT06N5i5aS5atKpsY/\nXRIVnRbIZDJycnKU9y0sLLgZe0Py3CYeHpJnvA+54VfCsK/iwKRJk6jn5kK71p6EXQ6VJKtxk//e\ntvArYXRq24r6tVwYMXwIz54903h2hQoV8G7dBoDs7Gw2bVxH5y5dNZ6jzcya9ta0qlORRfuvKB87\nf/0hNxNSlPfb1rfj8F93X1mutKUxvp7VWXpAc6cWbWxsaNuuvfJ+YMARGjV219j6X9bY/fXPkbe3\nN8cCAnianMzz588JOHIIz1atJclXlZ5M9ZtOy63b+A+Dp1crTh4/xrWrEWRnZ7NyxTKeP3+u62IV\nG8+ePeVqRDgfffQRoRFR9O7TF9+ePcjOztZKvpOTEx07f8zWXfs4ExxCakoK/hO+lixv6eKFlCtX\njrNnzjD7ux8ky9FG5uLhLRi76izZOa8Pt3X02y4A7D9/mxNh917525ed3Nj6xw1SM+UaK8vLjh8/\nzuJFC5g77ydJ1v9funbtilvt2jg7VKSaXTmePXtK/0FDtJZfGOKITsuCg4MZNWqUrotRKC6uNZj3\n00IG9PPF3d0dF9calChZUtfFKjasrEpgU64cXbvmHWkMGDSE5OQnxMREayW/adOm+E+bgaWlJWZm\nZnw9fhK/HzkkWd4Iv9EkJSUx0m80rVo2IzNTM6futJ05uK0rkXHJnIt8+J9/bzPlAAAudtbM+bzx\nK3/r9VE1tp+W5qzI/n17GTBgALv2HlCextSGRYsWkZSYyK37Sdx+8BhnlxpMHi/dDyZViDY64a36\n9uvPhZArXLp0iRo13ahZs5aui1RsVLa3Jy01ldzcvAFxZTIZenp66OtpZ6DbuLg4khITlfdzsrMx\nNDDUeE5UZCQnjh8D8raxZ+8+pKakEH1dunY6KTM7u9vTuXEVbq39jFtrP6NSaXPOzOtO58b22JUx\nVz5v44nrtK5XSXm/um0JzE0MuXzzsdpl+LcTx48xfuwYAgMDadCgocbX/zaBgYF0/rgbZmZmGBgY\n0LX7J5w7I03vYVXJ1LjpUpGu6NLT0xk3bhxdunRhyZIlXL9+nb59+9KvXz+GDx/O06dPCQ4OZtiw\nYfTr14+IiAjmzJlD79698fHxYffuvA4hgYGB9O7dm88++4wfftD8qaDY2Bs0bVyfp0+fIpfL+d+P\n39O33+caz/lQ1XSrRfkKtvz6668A7N61g5Ilranq6KiV/OXLlzPqq6HI5XJycnL4ZfkS2nboqPGc\npKREhgzqz/379wEIOncWuVyOQ9WqGs/SRmb32b9jP2AjDgM34TBwE/GP02k+fg+dG1dhSu+GyqOA\n9g0qE3H7iXK52g6lib73VO38f8vIyGDYF4P4bfsuXF1dNb7+gjg7O3Ms8HflKffA3w/jWkNzl05o\ngp5MpvJNpxRF1Pnz5xUtW7ZUZGRkKNLS0hTu7u6Kfv36KS5fvqxQKBSKX3/9VbFw4ULF+fPnFZ6e\nnooXL14okpOTFd7e3gqFQqHIyspSbNu2TZGWlqbo1q2b4sWLFwqFQqEYNWqU4q+//nprdnZO7juX\n95tvvlFUrlxZYW9vr5g0adI7L/+uEhISFM7OzgpnZ2cFoHB0dFQ4Ozsr4uPji2Xu1atXFY0aNVI4\nODgo3N3dC3wPVfG2bevfv7+iWrVqCicnJ8WAAQMUT58+1Xi+QqFQLFmyROHq6qpwdnZW1K5dW3Ho\n0CFJcnSdqQtbtmxRGBsbK9/j/FtCQoJGc972OfL19VU4OjoqqlevrujUqVOhvjfJGdkaLd/bnItJ\nVvmmSzKFQsVJl3QsODiY9evXs2zZMgDc3d0xMDDg7NmzAERERLBkyRIGDhzI2rVrWbFiBQBDhgzB\n0NCQ9u3b06FDByIjIxk6dChOTk4ApKamMnjwYLp06fLG7LQXqk+YZmGsp9LyBvqqH3ybGMBz7fTL\n0EimqnPDmRvJSM9SbVl15qOzMtEj5fm7v6eGaswxaGooI1Ou3a+uOpmlfFaptFzm3qGYdtP+fHTq\nbKuqc8qVNNXnaWZOwU98w7LacP6G6kfSTarprl9CkR4CzMDgzcWXy+Xo6eVVDkZGRsrHf/31V65e\nvcrBgwfZt28f48aNw83NjdWrV0teXkEQhCJN141tKirSbXT/Vr16dUJD866funjxIm5ubq/8PT4+\nng0bNlCzZk0mTpzI06dPcXBwIDY2lseP8xq2Fy1axMOH/90LTBAE4UNWVC8vKNJHdP82depUZs6c\niUwmo0SJEnz//fdcvfrPyAI2NjaEhoZy+PBhDA0N6dGjB6ampvj7+/PFF19gZGREjRo1sLGx0eFW\nCIIgvJ903adEVUW2jU6XRBudtJmija5goo2uYKKNTvMu3lR9xJ9GVV8fxk1bitURnSAIgiChInpE\nJyo6QRAEoVB03damqmLVGUUQBEEQ/k0c0QmCIAiFUlQ7o4iKThAEQSiUIlrPiVOXgiAIQiFJPKpz\ndHQ0rVu3ZtOmTQA8ePCAfv364evry+jRo8nKygJg//799OjRAx8fH3bs2FHgekVFJwiCIBSKlBeM\nZ2RkMHv2bDxemrh50aJF+Pr6smXLFuzt7dm5cycZGRksXbqUdevWsXHjRtavX8/Tp28fmkxUdIIg\nCEKhSDkfnZGREatWrXplwI7g4GC8vb0B8PLyIigoiLCwMGrVqoWlpSUmJibUr1+fkJCQt65btNEJ\nb6X6eAIylZfV11O9JUDVZdXJBDAy0P5vRpkOegaompm8c6jKmaoua+05VeXMzDNzKOU1TaVlHx6b\npXKuzqezKYCUpTMwMHht/OLMzEzlWMWlS5cmMTGRpKQkSpUqpXxOqVKlSHxpPsj/XLfmiysIgiAU\nSzqsh9/0w7kwP6jFqUtBEAThvWRmZsbz588BePjwITY2NtjY2JCUlKR8zqNHjwocn1hUdIIgCEKh\naHv2gqZNmxIQEABAYGAgLVq0oE6dOoSHh5OSkkJ6ejohISE0bNjwresRpy4FQRCEQpGyCTEiIoK5\nc+dy7949DAwMCAgIYP78+UyaNIlt27Zha2tLt27dMDQ0ZOzYsQwePBiZTMaIESOwtLR867pFRScI\ngiAUipRNdG5ubmzcuPG1x9euXfvaY+3bt6d9+/aFXreo6ARBEITCeb87hb6RaKOTkFwuZ/LEcVia\n6HMvPl75eOKjR3zcsS11ajhJnj9x/FhkMhnxL+VL6eCB/bg3rIerqyveni24GhEheeapkyfwaFQf\nJycnOrVvo7Vt1cXrq8ttHTt2LKaG2tlWbWxnew8nMs/MoXL5kqz9xofLm0crbwC/zekDQM2q5Qhc\nPJjQTaP4a4Mf3VrWUDtbLpczZeI4Spj+s29Yt24dduWsaVinhvK2cvlStbM0qajOMC4qOgn1/rQb\nFuYWrzz25MkT2rfxooZbLcnzfT7pioWFRcFP1JB79+4xdPAA1m3YTGRkJD1798FvxHBJM9PT0/m8\nb2+W/fIr0dHRdOzUhVESZ+bT9uv7oWyrNrbT1NiQ2cPb8vhZBgADZ+2gbt+FyhvAxiN5FyFvmdOb\nxdvPUe+zRQyevZNVU3pgbWmqVn4fn26Y/8fr2fnjbvwVdk15G/rlCLVyNE3KC8alJCo6CU2YPJUp\n38x45TGZTMZvO3bTqVMXyfMn+U9j2vSZkufkMzQ0ZN3GLbjWyPvF27RpcyKvXZU089TJE1RxqEq9\n+vUB6D9wEMeOBpKamippLmj/9dX1ts6cqZ1t1cZ2Th3Uit8CLpOW8eK1v7VtUh2Aw2evY6Cvx5zV\nJzhwOhKAsJgHPM/KpnL5kmrlT5g0Ff9pM9Rahy5IPNSlZERFJyH3Jh6vPWZtbY2Tk7NW8pt4vJ4v\nJRsbG9q2+6eBODDgCI0au0uaGRMTTdWqjsr7FhYWlC5dmtgbNyTNBe2/vh/Ktkq9nTWrlqNVI0cW\nbTv3n3+fNshb+f/snFx2HA9X3u/SwpWnqZlE3n6kVhka/8e+ASD8Shid2raifi0XRgwfwrNnz9TK\nEfKIik6QxPHjx1m8aAFz5/0kaU5mRgYmJiavPGZiakp6erqkubrwoWyr1Nu5eNzHjF1wiOyc3Nf+\n9lE9h/88zeZe046YXeNZ8HUXhn+/hyx5jkbK8jInJyc6dv6Yrbv2cSY4hNSUFPwnfK3xHLUU0UO6\nYl/RBQcHM2rUqNce//bbb4mLi9NBiYq//fv2MmDAAHbtPaA8jSkVMzNz5cgJ+TIzMrTadqYtH8q2\nSrmdg7s2IvJ2Iueu3PnPv/dqU4ftx6689njw1Tiq95hHt/Eb2DCzF7WqlVe7LP/WtGlT/KfNwNLS\nEjMzM74eP4nfjxzSeI46RGeUImbKlCnY2dnpuhjFzonjxxg/dgyBgYE0aPD20Qo0wdnFhdjYf05p\nPXv2jOTkZKpVry55trZ9KNsq5XZ2bu5C5xYu3No3kVv7JlLJpgRnVn3JR/UcAOjQ1Infg6KVz7e2\nNKV3mzrK++E3ErhwNY6Wfz9fk+Li4kh6aXDinOxsDA0MNZ6jDtEZ5T1x//59+vbtq5ys7/79+6Sn\npzNu3Di6dOnCkiVLAOjXrx/R0dEsXryYKVOmMGjQILp06cKff/6p4y0oujIyMhj2xSB+274LV1dX\nrWS29PQi7u4dzp45A8DihT/ToVNnzM3NtZKvTR/Ktkq5nd3Hb8S+yw84dJ2LQ9e5xD96RvMvlvNn\n6C3KljSnbElzYuIeK58vz87hp68707J+VQDKljSnUY1KhMc+VLss/7Z8+XJGfTUUuVxOTk4Ovyxf\nQtsOHTWeo44ieuYSFMXMmjVrFEuWLFEoFApFRESE4pdfflG0bNlSkZGRoUhLS1O4u7srFAqF4rPP\nPlNcv35dsWjRIsXgwYMVCoVCERUVpejatWuBGdk5uQU+JyEhQeHs7KxwdnZWAApHR0eFs7OzYt26\ndQpnZ2eFnZ2dwtDQUOHs7Kxo1aqVGlv8bvnx8fEaz8q3ZcsWhbGxsTI3/5aQkCBZpkKhUJw8eVJR\nu3ZthaOjo6Jdu3aKBw8eSJqnUOjm9VUoPpxt1cV2asvbXs/+/fsrqlWrpnByclIMGDBA8fTp0wLX\n9ywzRwulznM9IV3lmy7JFAqVJxx7L0VHRzNy5EhatWpFu3btyMrKYv369SxbtgwAd3d3goOD6dev\nH9OmTSMgIAAzMzMGDx4MgIeHB0FBQW/NSHvxeiN2YVkY66m0vIG+6gffJgbwPFu1ZVX9eJgaysiU\nq7asqnOeqbOd6tBFrsgsmLrz0Zk2V215VeejszLRI+W5avsWKxPtnJyLeZip8rLVy6l37aE6it2p\nSycnJ/bt20fDhg356aefePDgwWuT+f1bbq7qFZcgCMKHQrTRvScOHTpETEwMrVu3ZvTo0axevbrA\nZS5dugRAVFQUtra2UhdREARB0KJiN6hzlSpVmD59OmZmZujr69OnTx/Onz//1mUsLCwYPnw49+7d\nw9/fX0slFQRBKFp03qlERcWuoqtZsyY7d+585TFfX1/l/4ODgwGU00EEBARQt25dPvvsM+0VUhAE\noSgqojVdsavoBEEQBGno+sJvVX3wFZ2fn5+uiyAIglAk6LpTiao++IpOEARBKJwiWs+Jik4QBEEo\npCJa04mKThAEQSiUotpGV+yuoxMEQRCEl4kjOkEQBKFQRGcUQRAEoVgrovWcqOgEQRCEwimqR3TF\nbvYCbVB1VH5QfVT/nFzVM1WdMQFUnzWhqI10X9RyRWbBctX4zpgZycjIUm350u6qXZubGboE03oj\nVV5WG+KTs1RetpK1kQZL8m7EEZ0gCIJQKEX1iE5UdIIgCEKhFNF6TlR0giAIQuEU1SM6cR2dIAiC\nUKyJIzpBEAShUMTIKMJb7d29C/eG9XBxccHbswVXIyIkz9y4fi0N67rh6urKxx3bEhMTLXkmgFwu\nZ+zYsZgayoiPj5c879TJE3g0qo+TkxOd2rfRSqauckWmdO7cvk0JcyPq1XLFxcWFerVcGTKov0Yz\n2jevSWboEipXKIW5qRG/zPiMsD3TuHZgxivP09fXY6F/L2KOzCZi33SG+rTQaDlUJlPjpkOiotOC\nuLt3GTXyS3bs2ktUVBSf9PiU4UMHS5p5/XoUU/0nsv9QAJGRkXTt/glfDR0iaWY+n0+6YmFhoZWs\n9PR0Pu/bm2W//Ep0dDQdO3Vh1IjhxTJXZErPtmJFQsMjiYqKIjQ8kl/XrNfYuk1NDJk9qiuPn6YD\nMPmLDpibGlH3kzm0GbwAAHvb0gCMHdCGcqUsce70DV4D/kfP9g2wtjLTWFlUVUTrOVHRaYOBoSFr\nN2ymsr09AJ5e3sREX5c0MyryGo7VqmNbsSIAH3m2IvKa9EeRAJP8pzFz5kytZJ06eYIqDlWpV78+\nAP0HDuLY0UBSU1OLXa7IlPY9ldrUYR357dAF0jKeA9CqiQsbD5xHoVBw79FTALp41gKgf9cm/Lgm\nkNxcBYnJabQevIDklAydlT2fTKb6TZdERacFFSpUwLt1GwCys7PZtHEdnbt0lTSzceMm3LoZy7Wr\nESgUCvbt2Y2Xd2tJM/M18fDQSg5ATEw0Vas6Ku9bWFhQunRpYm/cKHa5IlPa9xQgNSWFXp92x8XF\nha6dOxAVGamR9dasZkurJi4s2nxC+ZhCoUBf79VdsKNdWcxNjahqV5aGNe05v3USwdsm0at9Q42U\nQ10yNf7pkuiMokVLFy/k+29nU9WxGtt27pE0q4KtLdNnzqFp4/pYWlpiZm7OkcCTkmbqQmZGBiYm\nJq88ZmJqSnp6erHLFZnSvqcWlpb07NWH0f83Dudq9syd9xO9Pu3GpbCrGBiot6tcPKUXY+fuIDv7\nnxGKTgRHMaznRxw/H4VNKUsAjI0NKWmZd4rSroI1Hn3mUqu6LUdXjyE0Ko7o2w/VKofadH0OUkXF\n4oguICBA5WX79etHdLR2OmmM8BtNUlISI/1G06plMzIzMyXLCrscyvy53xMeeYPk5GRmzv6OXp92\no7iN+GZmZs7z589feSwzI0PyNkJd5IpMad/T0qVL89PCJdhXqYKenh6jxnzNo0cP1e7ENbhHMyJv\nJnDu8s1XHv9+5e/cT3zKxe3+LJrSG4BnqZk8S8vbL6zZfQ6FQsGV6Hv8eekGno2c1CqHJog2Oh2J\nj4/n0KFDui7GW0VFRnLi+DEAZDIZPXv3ITUlhejr0rXTnTp5AvcmHthVrgxAD59eREVeIykpSbJM\nXXB2cSE29p9TWs+ePSM5OZlq1asXu1yRKe17mpyczO1bt155LCcnB0MDQ7XW29mzNp09a3Pr6Hfc\nOvodlcpZc2bzeBq62fPlzC3U7jaL7n7LAYi4cZ+0jBc8eZZOCYt/jmpzc3LJyVVtvFqhGFR0s2bN\n4sKFC7i4uDBhwgR8fX0JCgpi1KhRyue4u7sDcO3aNXr16kXv3r2ZO3fuK+tJS0vDx8eHmJgYjZcx\nKSmRIYP6c//+fQCCzp1FLpfjULWqxrPyVXdyIvh8EI8fPwYg4PfDlCtfnjJlykiWqQstPb2Iu3uH\ns2fOALB44c906NQZc3PzYpcrMqV9Ty/9dZGO7bxJTEwEYO3qVdjZVVb7e9rdbzn23pNxaOOPQxt/\n4h8m07zvPBq52fPD190BcKlaHoCDJ68AsDMwhNH9vIG8npgtGlbnz780v296V0W1M0qRb6MbPHgw\nmzdvpnr16ty8eZMtW7YQHBz8n8+dM2cOM2fOVFaK9+7dA/IahSdOnMjIkSOpLsGvxuYtPmLCJH86\nt2+DQpGLkZEx6zf9hpWVlcaz8nXs1IXLISF4t2yGvp4MC0srNmzehkziT9zDhw9p691SeaqiXWtP\nDAwMOBxwnIp/9wDVJFNTUzZs3sr/jRpBRkY6VR2rsXL1Oo3nvA+5IlNardu05YthX9Laszn6+nqU\nr1CRzVt3oq+vL0nexv3BbPhhINcOzCDzhRxAedpyyoK9rJz5GdGHZ5GW+YKv5+4g5s4jScrxLnTd\nqURVRX6anuDgYGVFZ2FhwcCBA5WPLVq0CMg7ogsODsbDw4OgoKBXlu/Xrx/W1tbY2NgwderUQmXm\nKhTo6foniiAIAmBab6TWpulJzshReVlrM2l+MBRGkT+ie5mhYd659H8ftWRn501opaf332dqrays\nOHv2LMnJyVhbWxeY8yIbQLXfB2I+OumI+ehE5ss+pPnohLcr8m10enp6yoosn4WFBY8e5R3mR0VF\nKbslOzo6EhYWBoC/vz+xsbEAfP755wwZMoQ5c+ZoseSCIAhFS1FtoyvyFZ2joyPXrl17ZdQEFxcX\nzMzM6N27N/v27VO2DU2ZMoUffviBPn36UKJECRwd/7kotUePHjx79ozjx49rfRsEQRCKgqJ6wXiR\nb6PTBVVOPeYTpy6lI05disyXfUinLrXVRpfyXPVLHKxMdHdcVeSP6ARBEAThbYpVZxRBEARBOkW1\nr7mo6ARBEITCKaI1najoBEEQhELRdacSVYmKThAEQSgUXV8moCpR0QmCIAiFUkTrOVHRCYIgCIUk\nYU333XffERYWhkwmw9/fn9q1a2ts3aKiEwRBEApFqja6CxcucOfOHbZt20ZsbCz+/v5s27ZNY+sX\n19EJgiAIOhUUFETr1q2BvNGunj17RlpamsbWL47oVGBqqN6vGtWWVy/Twlj7v2lMdPDp0kWmrnJF\nZkHU+86YGam2vDqjlGhrhBNVmao3B+0bJSUlUbNmTeX9UqVKkZiYqLFZ5cURnSAIgvBe0fTIlKKi\nEwRBEHTKxsaGpKQk5f1Hjx5RtmxZja1fVHSCIAiCTjVr1oyAgAAArl69io2NjcZOW4JooxMEQRB0\nrH79+tSsWZPevXsjk8mYPn26RtcvpukRBEEQijVx6lIQBEEo1kRFJwiCIBRroqITJJebq/qsxIIg\nCOoSFZ0giWvXruHn5weAnp6e5JVdbm4u2dnZkma8TX5Tt7aavP+do4sfE6J5X/PEayoNUdG9x7T9\nof+vPFV3oK6urmRkZDB+/HhA2spOoVAQEhLCrVu3CA0NJSsrS5Kct+XL/p6/JC4uTiuZMpmMy5cv\na+X1/be4uDgSExOV26wN78N3QRtlyH9Nnzx5InnWh0RUdO+B/C/QpUuXOHfuHOfOnQPQ+o4kP+/c\nuXMcOXKEhw8foqf3bh8RhUKhXNeXX35JREQEEydOBKTbGctkMoyNjfn6668ZP348mZmZGs8oKB/g\n7NmzzJs3D4CcnBxJMy9dusSFCxcICgpi0qRJgPQ/JgCio6NZs2YN27dvJzk5+ZW/SSn/NT58+DA/\n//wzZ86c4eHDh5Jk5X9+g4KC2LRpEzt27FCWQaptjY2N5fHjx8ofbf7+/sjlckmyPkSionsPyGQy\nzp49y88//8yDBw9YuHAhR48e1XoZALZu3cqqVau4c+cOn376KbGxsUDhd2YymQyZTMbmzZv57bff\nGDFiBPHx8YwaNQqQbmdco0YNvLy8sLa2JiYmRus7ifDwcNatW4eLiwsA+vr6kmVFR0fj7+9Ps2bN\nWLJkCU+ePGH06NGAtD8m/vjjD+bMmYNcLickJITt27crj+y0Udlt27aNPXv24OzszNy5cwkNDZUk\nRyaTceXKN8rkAAAfVUlEQVTKFebNm4dMJmPTpk3Mnj1b+TdNUygULF26lIULF5KSkoKjoyN2dnYY\nGv4zsKRo51aPqOh0LDc3l+fPn7Nt2zZmzJhByZIlKVGiBO7u7iQmJkqef+vWLX7//XfkcjlPnjzh\n/PnzrFy5Ent7e+rUqYOjoyNZWVkFfsH/vaMLDQ3Fy8uLzp07s379ejIyMl45stOkkydPEhQURM+e\nPZkyZQoLFizg9OnTAJJVeC9vb05ODjVq1KBRo0bEx8cTFhYm6RGdubk5NWrUwNramrp167J48WLu\n3bvH5MmTgbzXV9MVT25uLseOHaN///7MmTOHvn378vTpU/bu3cuTJ08kqwBezr9//z7z589HX18f\nBwcH2rdvrzyqU3d7ExISuHz5MpD3ndi2bRt9+vShb9++bN26lb/++ovvv/9erYz/kpubi0wm47vv\nvkMul7N48WIeP35McnIyV65cUT5P09+ZD43+jBkzZui6EB+i/NMjOTk5GBkZER0dzfXr1/njjz/4\n5ptvKFOmDHv27MHNzU2yU5iZmZkEBgZy9epVcnNzcXFx4fr166xatYr4+HgWL17MnTt3WL16Ne7u\n7m/9suWXcf/+/Vy7dg0bGxsSEhKwtbWlZMmSVK1aleXLlxMXF4enp6fGtmHHjh1s2rSJkiVLsnLl\nSrp164abmxvLli0jIiKC0NBQmjRpovHXMH99W7Zs4cCBAwQHB9O3b19iY2O5du0a1tbWlClTRiM7\nqOzsbPT09IiKiiIhIYHMzEwSExNJT0/HwsKCUqVKIZfL+fPPP4mIiKBVq1Ya2d78z2h2djb6+vqc\nP3+eBw8e0Lx5cxwcHLhz5w7Hjh0jIyMDR0dHTExM1M78dzbAw4cPsbCwICQkhG+++YbU1FQWLlxI\neno68+fPx93dHWNjY7XyIiMjsbS0xNTUlNjYWCIiIkhISMDBwQEbGxs6duzI7t278fDwwNTUVBOb\niEKhUH4+Xrx4gbe3NwcPHuTChQs8ffqUXbt2ERsby+7duzEzM8Pe3l6rzRnFiajodEQmk3HhwgXW\nr19P+fLlAVi1ahVTpkzBxcWF4OBgtm7dire3t0Z3IPliY2M5evQoXbt2JSkpicjISFJTUylRogRx\ncXF06tSJatWqceHCBW7cuEGLFi3+83Rc/ukjS0tLTp8+zdGjR2ndujWurq6cOHGCzMxMypYty717\n96hUqRI+Pj6UKFFCI9tw//59VqxYwfLlywkPD+fWrVucOHECX19f7OzsSElJoXPnzpQuXVojef8W\nGBjIoUOHmDNnDlOnTqVcuXL069ePa9euce7cOSpUqICNjY3K63/y5Ammpqbo6elx8uRJFi1aRHR0\nNMnJyTx69Ihnz55x7949oqKiCAkJYfz48URFRdG4ceNXTnupSiaTce7cOXbt2kVYWBiffPIJCxYs\n4MmTJzRp0gR9fX3u3r1LRkYG9vb2Gh2EN3+HvmHDBvbt20dGRgadOnXixo0bWFlZ4eXlxenTp/nr\nr7/w8vJSufLJr1ArVqyIsbExw4cPp27dutSrV4+EhAQSExOxtrYmLS2N3bt307lzZ8zNzTW6jdu3\nb2fZsmXEx8czYsQIQkJCSE1NZdSoUbRp04asrCwaNmyIlZWVRnI/RKKi05GIiAgWL16MjY0Ny5Yt\nw8fHBxsbG/bs2cPly5fZv38/w4cPx9nZWZL8UqVKUalSJZKSkqhYsSIpKSnEx8djbGxM+fLluXTp\nEtu3b+f8+fOMHj36jTvs0NBQKlasiJGRETExMVy8eBFLS0uaNGlCmTJluHTpEocPHyYgIAA/Pz/s\n7Ow0Uv7AwECysrIoWbIkoaGhXLp0iV9//ZWwsDDmzZuHhYUFQ4YMUf6I0IT8nWL+6abjx49Tr149\n7t69S2ZmJn5+fly5coUuXboQGxtL48aNMTMzUykrNzeXUaNGKSeknDt3LhMnTqR79+7k5OSQlpaG\nmZkZZcuWJSgoiK5du6JQKDh48CBdunTByMhI7e0NDQ3lhx9+oFevXhw7doynT5/Sv39/1qxZQ1hY\nGOvXr2f69OlcvXqVrKwsatWqpXbmy0dyf/zxBwcOHGDBggWULVuWnJwcnJ2diYqKYs2aNVy4cIEp\nU6ZQsWJFlbJycnKUR1QJCQlYWlpSsWJF1qxZQ926dbGzsyMkJIQDBw4QHh7OsGHDNPJ9fHkbw8LC\nWLp0KYsWLaJMmTLY29vTrFkzgoKCuHfvHl5eXjRs2BBLS0u1cz9kYlBnHYiLi2P27Nl89dVXtGzZ\nEhcXF7799lumTJlCkyZNyMrKolu3btSuXVuS/OzsbAwMDChVqhT/+9//ABg8eDDnzp0jKSkJe3t7\nxowZQ1xcHHZ2dpQrV+6N6+rYsSNRUVH079+fTZs2oa+vT0BAADY2Nnh5eVG9enXS0tLIzc1963re\nxZ49e9i6dSsdOnTAw8ODmJgY6tevj76+Pg0aNKBWrVo0atRIo6Of5+bmKneKGRkZWFhY0KBBA+bN\nm4exsTHr168HYNeuXZQvX55hw4apnJV/SmvZsmX07duX6dOnY25uTtmyZTEzM8PNzY3o6Gisra3x\n8fGhadOm/PHHH+zbt485c+ZobLtDQkJo3bo1Hh4eeHh4MGfOHI4cOcLu3buJjIykTZs23L59m6io\nKD7//HO1816uAB49esStW7cwNzfn5MmTXLhwgVu3bpGamsqGDRtIS0vDwMBA5aOcJ0+esHz5ciZP\nnkxYWBizZ88mMzOT2bNn4+fnx88//8yXX35Jly5dCAgIoFSpUri6uqq9jfBqh5ZSpUpRu3ZtSpcu\njbW1NdnZ2Rw7doxRo0axdu1a5WdNUI84otOSl7/EhoaGXLp0icDAQLp160bNmjUxMTHhxx9/pG7d\nujT5//buPCqq8+Dj+HeGRQZZZFgFgdGBKgouBTWIghWKEFGLSzQqdYnVUD2xRlzyakSP1oYeW49S\nYrDBJS5xC6ipyBG0iCCjoizubMouERARFQdh3j88TE2qSapDYvD5/DkD97kXZu7vPvtbb+ksFJ5V\nWVmJqakpUqmUkydPcuXKFcLCwsjKyuLKlSsEBwdTV1fHlStXMDU1xdvb+7lfsqKiIqqqqrCxsWHf\nvn1cv36dpKQkcnNzmTFjBkZGRpw4cYKWlha6deuGhYWFTr6sGo2GJ0+esHXrVmbOnMno0aOxsrIi\nPz+fvXv3avuMFi5cqPO/X9v/7tChQ+zYsYOamhrtTcjOzo7W1lYKCgq0zcEvW5N7tqyCggIePHhA\ndnY2GRkZFBUV4ePjg6WlJdXV1ahUKvz8/OjcuTNdu3YlMDAQhULxUmXeunWLpKQk3N3dSUtL49y5\nc7i6upKeno6TkxPW1tb4+vryxRdf4OnpiYuLC3V1dZw6dYrw8HCUSuVLX+93rzshIYHExETee+89\nUlNTKS0tZcyYMcydO5fi4mIkEgm9evV6pX65mpoacnJytJ/bNWvW0L9/fxYuXEhISAhDhgwhKiqK\ngQMHolQqycnJoba2Fjc3N52MqD1+/Djr169nypQpxMTEUF5ezpAhQ5BKpdrBYFOmTNFZM+mbTgTd\nT6At5FQqFYmJibS2thIaGkp1dTV79+4lMDAQNzc3TE1NsbS0xN7eXufnUF9fz7p166ivr6eiooJt\n27Zx+/Ztjh07xrRp08jOzubGjRuMHDmSlpaWFza7NTc3k5CQgEqlorS0lOTkZN555x3u3r1LRkYG\nKpWKP/7xj7S2tnLu3DmGDh2qk2Y0eHoj1NPT45tvvqGmpgZHR0eMjY21ZQ0cOJCpU6fq9O+Xm5vL\n559/jq+vL0lJSXz11Vfap+0ePXowYsQI1Go18fHxFBcXs3TpUp00z169epWIiAjCw8Px9vamtLSU\nM2fOkJWVhaGhIXFxccyePRtnZ2ekUikmJiYv3bzV3NxMZGQkUqkULy8vYmJiUCqV+Pv7c+PGDcrL\ny7Uh9K9//YugoCC6dOmCvb29Th7Knn0IrKioYOvWrZiZmfHb3/6WoKAgAgICaG1t5fz58yQmJjJl\nypRXfnAyNzfH3Nycu3fvkpWVxbvvvotSqUShULBkyRJGjhyJr68vRkZGeHp6YmpqqtNWAqVSSVxc\nHDdv3mT9+vX8/e9/p7CwkJKSErKzs5kwYYJortQhEXQ/AYlEQlpaGlu2bEGhUHDixAmampoYN24c\nZWVlxMXF8fbbb9O7d+92Cbm2czAzMyMjI4PTp08TGxvL2LFjqays5MyZMyxYsACVSkVhYSEzZ858\n4ZesbWh3dXU1Z8+exd/fH39/fwICArh9+zanT58mPT2defPm4efn1y7NLnK5nOTkZFpaWpDL5Vy7\ndo3S0lIiIiJ0OiACwMjIiE8//ZSKigrs7e15++23KSoqoqysjIiICBobG/H09CQ4OBg/Pz+6du2q\nk3Lr6uooKipi/PjxKBQKhg0bxrVr1ygpKSE0NJQRI0YwaNAg4NXndunp6dGjRw9iYmI4ceIE1tbW\nNDY20q9fPxwcHKiqquLQoUOkpaUxffp0+vXrpw2nV63dPBtyDQ0NdOrUCXNzc06ePIlGo6F3797c\nvXuXAwcOkJycTGRkJE5OTq9UJkBmZiYbN27Ew8ODe/fuce7cOfr374+7uzuOjo4sXLiQP/3pT9qy\n7O3tX7qW/uw1ZmRkkJOTQ8+ePZk8eTLR0dHk5+ezadMmqqqqaGxsZNasWTg7O7/yNQr/IYKunVRW\nVhIbG8uQIUPQaDTs3r2badOmYWJiQmJiIsbGxjQ1NREQEEBNTQ1dunRpl+bKti+Zvr4+zs7OGBsb\nk5KSQl1dHd7e3nh6eqJSqTh//jyrVq2iZ8+eP/gkKZPJcHZ2pry8nMzMTBwdHenWrRsBAQGUl5ej\nVCrp06ePzkOnjbm5OQqFgoyMDL7++mtycnJYsmSJTkdXts3LkslkdOvWjW3btpGcnExSUhL3798n\nOjoaiURCVFQUTk5O2Nra6qzmCk8D9tKlSzQ1NWFhYYG1tTW1tbXcuHGDqVOn6qy/qI1MJiMxMZEH\nDx5gY2ODra0tpaWl9O/fn0GDBuHr68uwYcNwd3cHdDdxuu048fHxbNq0iYqKCh49esSoUaNITk6m\nubmZvn37MmjQIIYPH66TB4nc3Fz++te/EhkZyYABA3B3d6e+vp60tDQ8PDzo06cP48ePx8LC4pXL\ngv9cY2ZmJg8ePODIkSN06tQJpVLJxIkTWbt2LZcuXWLRokV4eXkhl8t1Uq7wHyLo2omBgQGffPIJ\nt27dwtfXFxMTE27fvs2OHTvYuHEj9+7d4+DBgxw8eJB169a1yxPcs0+SSUlJFBQU0Nrair+/Pzk5\nORQXF+Pp6Ylarebq1av85je/+dHNJTKZjF69enH//n3Onj2LsbExZWVlHDt2jL/85S9YWVnp/Hqe\nZWFhgZeXF4MGDSIwMJBu3brp9PhtK7zs2bOH9PR0AgMDuX37NgUFBdjZ2eHr60tycjLnz59n1KhR\nOm9mMjQ0xMHBgcTERGpqaigpKeHy5cusXLmS7t2767SstvJGjx6Np6cnhw4d4vHjx9pVZrp27Yql\npaVOa+fPfjaPHz/O7t27Wbp0KdbW1qhUKurr6wkICODLL79EX18fV1dXnU2zKSsr49GjR0gkEs6f\nP8/+/ftRq9VkZmZy8+ZNfH19MTY2fuU5kA0NDVRXV2Nubk5mZiaffvopc+fOxcjIiMTERKRSKS4u\nLpibm5OWloa/v/8r9e0KLyaCrh08efIEQ0NDxo0bR1xcHNeuXWPSpElIpVIqKysZPXo0zc3NuLq6\nMmPGjHZtroSny3odPnwYmUzGlStXKC4uJiQkhN27d5OUlERpaSnh4eH/cw3MyMgIhUJBcXExW7du\npa6ujqVLl7ZLzfR59PT06Ny5c7vcHDQaDU1NTcTExDBhwgRCQkIYMWIEeXl5qFQq7t+/z+XLl1m8\n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\nogZPAtkAAAAASUVORK5CYII=\n",
            "text/plain": [
              "<matplotlib.figure.Figure at 0x7fc31e8cbf28>"
            ]
          },
          "metadata": {
            "tags": []
          }
        }
      ]
    }
  ]
}